Access Control and AuthorizationLesson 5.3
Mass assignment vulnerabilities: how to prevent field injection attacks
mass assignment mechanics, req.body spread, whitelist vs blacklist fields, Mongoose strict mode, DTO pattern, allowlist-based field filtering
Mass Assignment
Mass assignment happens when you pass a user-supplied object directly to a database update without restricting which fields can be changed. Attackers add extra fields (like isAdmin: true or role: 'admin') to escalate privileges.
The Vulnerability
// VULNERABLE — attacker sends { name: 'Bob', role: 'admin' }
app.put('/profile', authenticate, async (req, res) => {
await User.updateOne(
{ _id: req.user.id },
{ $set: req.body } // Spreads everything including role
);
res.json({ status: 'Updated' });
});The Fix: Allowlist Accepted Fields
// SAFE — explicitly pick allowed fields
app.put('/profile', authenticate, async (req, res) => {
const { name, bio, avatarUrl } = req.body; // Destructure only safe fields
await User.updateOne(
{ _id: req.user.id },
{ $set: { name, bio, avatarUrl } } // Only these fields ever update
);
res.json({ status: 'Updated' });
});
// Or use a validation schema that only allows specific keys
const schema = Joi.object({
name: Joi.string().max(100),
bio: Joi.string().max(500),
avatarUrl: Joi.string().uri()
});
const { error, value } = schema.validate(req.body, { stripUnknown: true });Mongoose Strict Mode
Mongoose's strict: true (default) ignores fields not in your schema during saves, but $set: req.body bypasses this because $set does a direct database operation. Strict mode alone is not sufficient protection against mass assignment via update operators.
