Skip to main content

Free 30-min security demo  — We'll scan your real code and show live findings, no commitment Book Now

Offensive360
Academy Mass Assignment
Intermediate · 20 min

Mass Assignment

Understand how over-posting user-controlled fields like isAdmin can elevate privileges through unguarded model binding.

1 Over-Posting and Model Binding

Mass assignment occurs when a framework automatically binds HTTP request parameters to model fields. If all fields are accepted, attackers can set fields they should not control.

Vulnerable Node.js/Mongoose:

app.put("/users/:id", async (req, res) => {
  // VULNERABLE: spreads all request body fields into user object
  const user = await User.findByIdAndUpdate(
    req.params.id,
    { $set: req.body },  // Attacker can set any field!
    { new: true }
  );
  res.json(user);
});
// Attacker sends: { "name": "Alice", "isAdmin": true, "creditBalance": 1000000 }

Rails strong parameters bypass:

# Vulnerable — permits all params
User.update(params[:user])  # Without permit() filter

# Attacker sends: user[role]=admin

This vulnerability was behind the GitHub mass assignment vulnerability in 2012, where an attacker added their SSH key to an organization repo by setting the org_id field.

2 Explicit Allowlists and DTOs

The fix is to explicitly specify which fields are allowed to be set through user input, either via allowlists or Data Transfer Objects.

Explicit field allowlist (Node.js):

const ALLOWED_UPDATE_FIELDS = ["name", "email", "bio", "avatarUrl"];

app.put("/users/:id", authenticate, async (req, res) => {
  // Only pick allowed fields — ignore everything else
  const updates = {};
  for (const field of ALLOWED_UPDATE_FIELDS) {
    if (field in req.body) {
      updates[field] = req.body[field];
    }
  }
  const user = await User.findByIdAndUpdate(
    req.params.id,
    { $set: updates },
    { new: true }
  );
  res.json(user);
});

Data Transfer Object (TypeScript):

interface UpdateUserDTO {
  name?: string;
  email?: string;
  bio?: string;
  // Note: no isAdmin, role, or creditBalance!
}

async function updateUser(id: string, dto: UpdateUserDTO) {
  return User.findByIdAndUpdate(id, { $set: dto });
}

Knowledge Check

0/3 correct
Q1

What is the root cause of mass assignment vulnerabilities?

Q2

Which pattern is most effective at preventing mass assignment?

Q3

What did the 2012 GitHub mass assignment vulnerability allow an attacker to do?

Code Exercise

Restrict Updatable Fields

The profile update endpoint spreads all request body fields into the database update, allowing attackers to set isAdmin. Restrict it to only allow name, email, and bio.

javascript