Mass assignment

Be careful with parameters that are automatically bound from requests to objects

Select your ecosystem

Mass assignment: the basics

What are mass assignment vulnerabilities?

To make it easier to save data submitted via an HTML form into a database or object, many web application frameworks have included libraries to automatically bind HTTP request parameters (typically sent via forms) to the fields of database models or members of an object, requiring only minimal coding.

Let’s say we have a (very simple) HTML form:

When the form is submitted to the web application, it will send the form data as HTTP request parameters, and the backend code will have to read each parameter individually into a corresponding variable. Then, once all the fields have been read, the application will usually execute a database update or insert operation to save the data.

Mass Assignment makes it possible to write less code to handle this process - think about how much coding this technique could save if it was an object that had dozens of fields, and multiply this across a complex application that has many of these objects in its database.

Mass assignment vulnerabilities occur when the database model that is being assigned contains security-relevant fields, and the application user can supply values in the POST request that are saved to those fields, even though they are not present in the HTML form.

For example, if the User model contained a field isAdmin: Boolean, the user could add the POST body parameter isAdmin=true and make themselves an administrator.

For this to occur, an attacker would need to guess the names of the sensitive fields, or the source code for the vulnerable application would have to be available to the attacker (allowing them to see what sensitive fields are present in the data model).

Impacts of this attack can include bypassing authentication or authorization logic or elevation of privilege. This could then result in the destruction or disclosure of data within the application.

About this lesson

In this lesson, you will learn how mass assignment vulnerabilities work and how to protect your applications against them. We will begin by exploiting a Mass Assignment vulnerability in a simple application. Then we will analyze the vulnerable code and explore some options for remediation and prevention.

FUN FACT

Mass assignment in the wild

In 2012, a GitHub user exploited a Mass Assignment vulnerability in GitHub’s public key update form. The flaw allowed the user to add their public key to another organization they were not a member of. The user added their key to the Ruby on Rails organization. To demonstrate proof of the exploit, the user added a file to the Rails project repository. GitHub responded, quickly fixing the vulnerability and they conducted a wide audit of their code to ensure the issue was detected and fixed if it existed anywhere else.

Mass assignment in action

New SaaS startup SuperCloudCRM recently launched their web platform designed to help businesses boost their sales and marketing efforts.

Mass assignment in action

  • STEP 1
  • STEP 2
  • STEP 3
  • STEP 4
  • STEP 5

Setting the stage

SuperCloudCRM recently launched its web platform. Unfortunately, they suffered a security breach, resulting in data being leaked. What went wrong?

Mass-assignment-start.svg

Mass assignment details

As mentioned, SuperCloudCRM’s developers had been logging request data for API endpoints like the POST /user/create endpoint, which creates new user accounts when a user submits the signup form.

A typical JSON payload in the request sent to the /user/create endpoint was supposed to look like this:

{
“username” : “jane.doe”,
“password” : “C0rr3ctH0r$3B@tt3rySt@pl3”,
“email” : “jane@somecompany.com”,
}

But a search of the /user/create endpoint’s logs for the 1337357h4xx0r.1244@hax4hire.xyz account around the time the user was created, found JSON POST data starting with the following excerpt:

{
“username” : “H4xx0r”,
“password” : “H4xx0rP@$$w0rd”,
“email” : “1337357h4xx0r.1244@hax4hire.xyz”,
“roker” : “test”,
“roky” : “test”,
“roland” : “test”,
“role” : “test”,
“roleplay” : “test”,
“roleplayer” : “test”,
“roles” : “test”,
“roll” : “test”,
...

It was different to the normal requests, and had a long request body with dozens more fields all starting with the letter r. What was the attacker doing? All of these weird field names that weren’t part of the user model schema, which was:

{
username: String,
password: String,
email: String,
organization: String,
role: String,
}

After doing some testing like the scenario above showed, a few things were discovered.

First, the new user account’s password was apparently being saved to the database in plaintext. Not good! But what stuck out was that the application ignored the non-existent fields and just assigned the fields that were actually part of the User model schema.

The data from the new User document was sent back to the API client and the attacker could then infer which of the list of fields starting with r were part of the User model schema, because if a field existed it was saved and echoed back in the response with the other user data.

A search of the /user/create endpoint’s request log entries around the same time revealed that thousands of similar requests had been sent. Each request testing lists of possible field names in the User model schema.

It was concluded that the attackers had brute-forced HTTP requests with various field name guesses to enumerate the organization and role fields in the schema. Despite them not being referred to anywhere in the client-side JavaScript code, the attackers were able to discover these security-related field names.

So, if the attackers knew these field names, what would they do then? Well, this could have led to a possible mass assignment attack. After hours of reviewing logs for the POST /user/create and POST /user/update endpoints the incident response team found dozens of requests had been submitted to the application, which looked similar to:

{
“username” : “H4xx0r”,
“password” : “H4xx0rP@$$w0rd”,
“email” : “1337357h4xx0r.1244@hax4hire.xyz”,
“role” : “administrator”,
“organization” : “dozipper.ly”
}

The requests appeared to be successful. Each of the requests changed the organization to a different customer, essentially giving the attackers access to each of them as admins. The last request was:

{
“username” : “H4xx0r”,
“password” : “H4xx0rP@$$w0rd”,
“email” : “1337357h4xx0r.1244@hax4hire.xyz”,
“role” : “administrator”,
“organization” : “cowmoo”
}

This seemed to explain why 1337357h4xx0r.1244@hax4hire.xyz was an administrator in the Cowmoo Industries organization.

By exploiting this mass assignment vulnerability and adding themselves as the administrator for various customers, the attackers were able to access the organizations’ data within SuperCloudCRM and steal it.

FUN FACT

Mass assignment by different names

The concept of mass assignment is known by different names in various programming languages or frameworks. NodeJS and Ruby on Rails call it mass assignment. It is referred to as autobinding in Java Spring MVC and ASP NET MVC. PHP calls it object injection.

Mass assignment under the hood

Let’s have a look at this vulnerable application in more detail by going through the server-side code.

The schema for the User model is defined here, with the user’s credentials, email address, plus their role and organization they belong to. During signup, the credentials and email address are the only values that are supposed to be supplied by the user and accepted by the application.

Impacts of mass assignment

By exploiting mass assignment vulnerabilities, a malicious actor could create multiple security problems including

  • Data tampering: Attackers can modify sensitive information in the database, such as password or account balance
  • Data theft: Attackers can gain access to confidential information stored in the database
  • Elevation of privilege: Attackers can manipulate the properties of an object to gain additional privileges, such as administrator access
  • Unauthorized access: Attackers can manipulate the properties of an object to gain unauthorized access to sensitive resources

Scan your code & stay secure with Snyk - for FREE!

Did you know you can use Snyk for free to verify that your code
doesn't include this or other vulnerabilities?

Scan your code

Mass assignment mitigation

Use an allowlist of fields that can be assigned to

Most mass assignment libraries or helper libraries should provide the ability to restrict the fields that will be read from a request and assigned to the data model. By restricting the assignment of user-supplied fields to only fields in the schema that are known safe ones, the values of security-sensitive fields will be prevented from tampering.

Using this strategy, the code for the application would be changed to add an allowlist using the pick() method of the underscore package and listing the allowed fields in the userCreateSafeFields array:

Use a Data Transfer Object (DTO)

Another option is to create an intermediary object (the DTO) that only has safe, assignable properties, which would be a subset of the target object that has those same fields plus any sensitive fields. Using our User example, the DTO would be:

The mass assignment operation can assign any user-supplied data to the DTO without the risk of inadvertently assigning any sensitive fields. The DTO can be copied to the final object, and during this process, any sensitive fields can be set to secure default values.

This method might require much more coding though. DTOs need to be created for all classes with sensitive fields. If there are many schemas with sensitive fields that require corresponding DTOs, then this becomes nearly as much work as not using mass assignment.

Use a denylist to declare fields that can’t be assigned to

The opposite of using an allowlist to define fields that are allowed to be assigned is to use a denylist of fields that shouldn’t be assigned. Security wisdom says to use allowlisting over denylisting because it’s safer to accidentally not include a safe field than to accidentally omit a dangerous field. So, following this advice, a denylist would be the less preferred option of the two. If there are 50 fields in a schema and only one is security-sensitive, then it is obviously much quicker to just denylist the one sensitive field. The danger here though would be if additional sensitive fields were added to the schema later and the developer forgot to add them to the denylist, then you would have a mass assignment vulnerability.

To use denylists, the code for the application would be changed in a similar manner to the code shown in the allow-list strategy shown earlier, except it would use the omit() method of the underscore package and listing the disallowed fields in the userCreateDisallowedFields array:

Utilize a static analysis tool

Adding a static application security testing (SAST) tool to your devops pipeline as an additional line of defense is an excellent way to catch vulnerabilities before they make it to production. There are many, but Snyk Code is our personal favorite, as it scans in real-time, provides actionable remediation advice, and is available from your favorite IDE.

Keep learning

To learn more about mass assignment vulnerabilities, check out some other great content:

Congratulations

You have taken your first step into learning what mass assignment is, how it works, what the impacts are, and how to protect your own applications. We hope that you will apply this knowledge to make your applications safer.

We'd really appreciate it if you could take a minute to rate how valuable this lesson was for you and provide feedback to help us improve! Also, make sure to check out our lessons on other common vulnerabilities.