app.patch("/api/users/me", requireAuth, async (req, res) => {
const user = await User.findByIdAndUpdate(req.user.id, req.body, { new: true });
res.json(user);
});
An attacker can make themselves an admin, because the handler saves whatever fields the client sends. The attacker adds fields like these to the body:
"role": "admin""emailVerified": true"balance": 99999
The model then saves them.
This is mass assignment. The OWASP API Security Top 10 2023 puts it under Broken Object Property Level Authorization (API3). The same category covers the opposite problem, which this code also has. It returns the whole user document, so it can leak fields like the password hash.
The fix: allow only a list of writable fields for each role (an allowlist). Two ways to do this:
- Validate the body against a strict schema. The schema allows only
nameandavatarUrland rejects unknown keys. - Pick the allowed fields yourself before the update.
Also send responses through a clear output shape. Don't serialise (turn into JSON) the database object directly.
- The client can set privileged fields like role.
- This is mass assignment, part of API3:2023 BOPLA (Broken Object Property Level Authorization).
- Allow only a list of writable fields for each role.
- Use schema validation to reject unknown properties.
- Shape responses so they don't leak sensitive fields.
Read more