What is Mass Assignment?
Your app has a profile update endpoint. The form sends { name, email, bio }. But the API handler spreads the entire request body into the database update. An attacker adds role: "admin" to the request, and your app happily saves it — because nobody told it not to.
Mass assignment exploits the gap between what your frontend sends and what your backend accepts. The frontend might only show three fields, but the API endpoint doesn't know that. It processes whatever arrives in the request body, including fields the attacker invented.
This isn't hypothetical. It's how GitHub was famously hacked in 2012 — a user updated their public key by adding a user_id field to the request, associating it with a different account. The Rails mass assignment vulnerability led to sweeping framework changes. Over a decade later, the same pattern shows up in AI-generated code every day.
How does Mass Assignment work?
Mass assignment happens when request data flows directly into a database operation without an explicit allowlist of permitted fields. ORMs like Prisma, Sequelize, and Mongoose make this easy to do by accident — they accept any object shape that matches the model.
Here's a typical vulnerable pattern in a Next.js API route:
// app/api/users/[id]/route.ts
export async function PATCH(req, { params }) {
const body = await req.json();
// DANGER: ...body includes EVERY field the client sends.
// An attacker can add { role: "admin" } or { credits: 9999 }.
const user = await prisma.user.update({
where: { id: params.id },
data: { ...body },
});
return Response.json(user);
}// app/api/users/[id]/route.ts
export async function PATCH(req, { params }) {
const body = await req.json();
// Only allow fields the user is meant to update.
const { name, email, bio } = body;
const user = await prisma.user.update({
where: { id: params.id },
data: { name, email, bio },
});
return Response.json(user);
}Why do AI tools generate Mass Assignment vulnerabilities?
AI code generators love the spread operator. It's concise, it's clean, and it makes the code look elegant. The problem is that elegance and security are pulling in opposite directions here.
- Spread patterns are idiomatic. Training data is full of { ...req.body } patterns. They appear in tutorials, docs, and Stack Overflow answers because they're the shortest way to wire up an update endpoint.
- The AI doesn't see your schema. It doesn't know which fields are sensitive. To a language model, "role" and "name" are both just strings. It has no concept of which fields should be user-controlled.
- Validation is conflated with filtering. AI might add type validation ("name must be a string") but skip field filtering entirely. Valid data and permitted data are different things — the model rarely makes that distinction.
Every time an AI generates <code>data: { ...body }</code>, it's creating a mass assignment vulnerability. The code works, the tests pass, and the door is wide open.
Common Mass Assignment patterns
Spread operator into ORM update
prisma.user.update({ data: { ...req.body } }) — the classic pattern. Every field in the request hits the database.
Role escalation via hidden fields
Adding { role: "admin" } or { isAdmin: true } to a profile update request.
Price or credit manipulation
Setting { price: 0 } on an order update or { credits: 99999 } on an account endpoint.
Ownership transfer
Including { userId: "attacker-id" } in a resource update to steal ownership of another user's data.
How Flowpatrol detects Mass Assignment
Flowpatrol finds mass assignment by doing exactly what an attacker does — sending fields that shouldn't be accepted and checking if they stick:
- 1Identifies update endpoints by crawling your app and detecting PUT, PATCH, and POST routes that modify data.
- 2Injects extra fields like role, isAdmin, permissions, and price into legitimate request bodies.
- 3Reads back the object to check whether the injected fields were persisted to the database.
- 4Reports which fields stuck with the exact request, the modified response, and the specific field allowlist you need to add.
This is the kind of logic bug that static analysis can't catch. Flowpatrol tests your live app with real requests to find fields your API should reject but doesn't.
Related terms
Check your API for mass assignment.
Flowpatrol tests your endpoints with injected fields to find unprotected object binding. Paste your URL.
Try it free