This article teaches mass assignment (autobinding/over-posting), a vulnerability where backends blindly copy all fields from a request into a data model without validation. The lab demonstrates how an attacker can add an 'is_admin' flag to a signup request that the form never exposes, gaining admin privileges because the server lacks a whitelist of permitted fields. This vulnerability remains common in real-world APIs and maps to OWASP's Broken Access Control category.
- Mass assignment copies unfiltered request fieldsThe vulnerability occurs when an application uses bulk-binding to map incoming JSON request fields directly into a database model without explicitly whitelisting which fields are allowed. In the lab, a signup endpoint accepts username, email, and password from the form, but the backend copies every key from the entire request body into the User record, including hidden sensitive fields like is_admin that were never intended to be user-controllable.
- UI form fields do not constrain backend acceptanceThe form visible to a user only displays certain fields (username, email, password), but nothing technically prevents an attacker from adding extra fields to the raw JSON request before submission. The server has no mechanism validating that incoming requests match the form's intended shape, so an attacker can inject is_admin: true into the JSON body and the backend will honor it without question.
- GitHub 2012 case demonstrated real-world impactResearcher Egor Homakov exploited a mass-assignment flaw in Ruby on Rails to add his public key to an organization he did not own, proving the vulnerability was not theoretical. This famous incident shows how the same class of attack—over-posting role, balance, or owner_id fields—persists across many APIs today and has led to its classification under OWASP's Broken Access Control (A01).
- Whitelisting prevents bulk-binding exploitsThe primary defense is to use explicit allowlists (implemented via strong parameters, data transfer objects, or similar mechanisms) that specify exactly which fields each endpoint may accept and set. Instead of blindly copying the entire request body, the server must validate against a whitelist before binding any data to the model, rejecting or ignoring any fields not on the approved list.
- Separate input models from database modelsA architectural defense is to maintain distinct models: one for accepting user input (which contains only safe, non-privileged fields) and one for the database (which includes all columns including sensitive ones like is_admin). This separation ensures privileged fields are structurally impossible to bind from a request, even if code logic fails.
- Read-only enforcement at data layer adds protectionMarking sensitive fields as read-only at the database or ORM layer prevents them from being set by any user input, creating a secondary safeguard. Even if an attacker adds is_admin to a request and the application fails to whitelist, the data layer itself refuses to modify read-only columns.
- Testing requires probing for hidden fieldsSecurity testing for mass assignment involves adding unexpected fields (is_admin, role, balance, owner_id, verified) to create and update requests to see if the server honors them. By deliberately sending fields the API never exposed or documented, testers can discover whether the backend lacks proper whitelisting.
Bottom line: Mass assignment is a critical vulnerability where servers blindly copy unvalidated request fields into models; prevent it by using explicit whitelists of allowed fields, separating input models from database models, and marking sensitive columns read-only. During API assessment, always test by injecting unexpected privileged fields into requests to identify whether the server honors them without authorization.
📋 In this walkthrough
What this lab teaches
Mass assignment (also called autobinding or over-posting) happens when an app bulk-copies request fields straight into a data model. It is convenient — one line binds the whole form — but if the model has sensitive fields the user should not control, an attacker can set them simply by adding them to the request.
The lesson: the fields a form shows are not the fields a server will accept. Without a whitelist, the server accepts whatever you send.
How QuickStart creates your account
Signup takes your details as JSON and copies each key into the User record. The visible form sends only username, email and password, but the User model also has an is_admin field — and the backend has no list of which fields a signup is allowed to set.
The attack approach
- Notice the signup body is JSON and the backend binds all of it to the user model.
- Reason that the User record probably has fields the form does not show, such as a role or admin flag.
- Add is_admin set to true to the signup request alongside the normal fields.
- Because there is no whitelist, the extra field is copied in and your new account is an admin.
Full walkthrough (spoiler)
If a normal signup leaves you as a plain user, add the field yourself — open the steps.
Show the step-by-step solution
- Take the normal signup request with username, email and password.
- Add one more field,
is_admin: true, to the JSON body. - Submit it. The backend copies every field — including is_admin — into the new User record, because it has no field whitelist.
- Your account is created with admin rights. The lab detects the admin flag and marks you solved.
Why it works
The server trusts the shape of the request to match the form. By binding the whole body to the model, it lets the client decide which columns to fill — including ones the UI never exposes. The is_admin field was always there; the form simply never sent it, and nothing enforced that.
Where this happens in the real world
The most famous case is GitHub in 2012, when researcher Egor Homakov used a mass-assignment flaw in Ruby on Rails to add his public key to an organisation he did not own. The same class — over-posting a role, balance or owner_id — remains common in APIs and maps to Broken Access Control (A01) in the OWASP Top 10 (2021).
How to defend against it
- Use an explicit allowlist (strong parameters, DTOs) of the fields each endpoint may accept.
- Separate input models from database models so privileged columns are never bindable from a request.
- Mark sensitive fields read-only at the data layer so they cannot be set by user input.
- Test by adding unexpected fields (is_admin, role, balance) to requests and checking whether they take effect.
Try it, then go further
Reading about it is the easy part. Open the lab, try your own approach before peeking at the spoiler, and see how many attempts it takes.
