Script Valley
Web Security Fundamentals for Developers
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 vulnerability diagram

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.

Up next

Privilege escalation: how attackers gain higher permissions

Sign in to track progress