TL;DR
Mass assignment happens when you pass user input straight into a database operation without filtering it first. Attackers just add an extra field, like "isAdmin: true", and your code saves it right along with everything else. Pick the fields you accept explicitly. Don't spread the entire request body.
How Mass Assignment Works
Vulnerable: spreading request body
// User registration endpoint
app.post('/api/register', async (req, res) => {
// VULNERABLE: saves whatever user sends
const user = await User.create(req.body);
res.json(user);
});
// Normal request:
// { "email": "user@example.com", "password": "secret" }
// Attack request:
// { "email": "user@example.com", "password": "secret", "role": "admin" }
Common Dangerous Fields
role,isAdmin,permissionsverified,emailVerifiedbalance,creditspassword(when updating profile)id,userId(changing ownership)
How to Prevent It
Safe: explicit field picking
app.post('/api/register', async (req, res) => {
// Only pick allowed fields
const { email, password, name } = req.body;
const user = await User.create({
email,
password,
name,
role: 'user', // Always set defaults server-side
verified: false
});
res.json(user);
});
// Or use a validation library
import { z } from 'zod';
const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string()
}).strict(); // Reject extra fields
app.post('/api/register', async (req, res) => {
const data = registerSchema.parse(req.body);
const user = await User.create(data);
});
Isn't this just bad input validation?
Yes, mass assignment is a specific type of input validation failure. It's common enough to have its own name because ORMs and frameworks make it easy to fall into by accident.
Does TypeScript prevent this?
No. TypeScript types are compile-time only. At runtime, req.body can contain anything. You need runtime validation with libraries like Zod, Yup, or Joi.
Scan for Mass Assignment
Our scanner detects endpoints vulnerable to mass assignment.