OWASP API Top 10 — API3

Mass Assignment

Mass Assignment is a critical security vulnerability that allows attackers to modify object properties that should not be user-controllable. By manipulating request parameters, attackers can escalate privileges, bypass security checks, or alter sensitive data fields.

What Is Mass Assignment?

Mass Assignment, also known as auto-binding or object injection, is a vulnerability that occurs when frameworks automatically bind HTTP request parameters to model object properties without proper filtering. Modern web frameworks often provide convenient features that automatically map request data to object properties, reducing boilerplate code. However, when used carelessly, this convenience can become a critical security flaw.

The vulnerability arises when an application accepts user input and directly assigns it to internal object properties without validating which fields should be modifiable. An attacker can exploit this by adding extra parameters to their request that correspond to sensitive fields like isAdmin, role, price, or balance. If the framework blindly binds all request parameters to the object, these unauthorized fields get modified, potentially granting the attacker elevated privileges or financial advantage.

Mass Assignment has been ranked as API3 in the OWASP API Security Top 10, reflecting its prevalence in modern API-driven applications. Despite being well-documented, it remains a common vulnerability because developers often trust framework defaults without implementing proper input filtering. High-profile breaches, including the 2012 GitHub incident where attackers used mass assignment to gain unauthorized repository access, demonstrate the real-world impact of this vulnerability.

How It Works

1
Application accepts user input

The application receives HTTP request data, typically in JSON or form-encoded format. This could be a user registration form, a profile update endpoint, or any other feature that accepts structured data from clients.

2
Framework auto-binds to model object

The web framework automatically maps request parameters to object properties based on matching property names. For example, a Spring Boot controller might use @RequestBody to bind JSON directly to a User entity, or a Rails controller might use params.permit! to allow all parameters.

3
Attacker includes unauthorized fields

Instead of submitting only expected fields like username and email, the attacker inspects the application code or makes educated guesses to include additional fields such as isAdmin=true, role=ADMIN, or accountBalance=1000000 in their request payload.

4
Sensitive properties are modified

Because the application does not restrict which fields can be bound, the framework assigns the attacker's unauthorized values to sensitive object properties. A regular user registration suddenly includes user.isAdmin = true, granting the attacker administrative privileges.

5
Object is persisted to database

The modified object, now containing attacker-controlled values for sensitive fields, is saved to the database. The application continues to operate normally, unaware that privilege escalation or data manipulation has occurred. The attacker now has elevated access or modified financial records.

Vulnerable Code Example

Vulnerable — Java / Spring Boot
@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String username;
    private String email;
    private String password;

    // Sensitive fields that should NOT be user-controllable
    private String role;        // e.g., "USER" or "ADMIN"
    private Boolean isAdmin;
    private Double accountBalance;

    // Getters and setters...
}

@RestController
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @PostMapping("/api/register")
    public ResponseEntity<?> register(@RequestBody User user) {
        // VULNERABLE: All request fields are directly bound to User entity
        // An attacker can include role=ADMIN or isAdmin=true in their request

        // Hash password before saving
        user.setPassword(hashPassword(user.getPassword()));

        User savedUser = userRepository.save(user);
        return ResponseEntity.ok(savedUser);
    }
}

// Attacker sends:
// POST /api/register
// {
//   "username": "attacker",
//   "email": "attacker@evil.com",
//   "password": "pass123",
//   "role": "ADMIN",
//   "isAdmin": true,
//   "accountBalance": 1000000.0
// }
//
// Result: Attacker gets admin account with $1M balance

Secure Code Example

Secure — Java / Spring Boot (Using DTO)
// Data Transfer Object with ONLY allowed fields
public class UserRegistrationDTO {
    private String username;
    private String email;
    private String password;

    // Getters and setters...
}

@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String username;
    private String email;
    private String password;

    @JsonIgnore  // Never expose in API responses
    private String role;

    @JsonIgnore
    private Boolean isAdmin;

    @JsonIgnore
    private Double accountBalance;

    // Getters and setters...
}

@RestController
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @PostMapping("/api/register")
    public ResponseEntity<?> register(@RequestBody UserRegistrationDTO dto) {
        // SECURE: Only accept allowed fields via DTO
        User user = new User();
        user.setUsername(dto.getUsername());
        user.setEmail(dto.getEmail());
        user.setPassword(hashPassword(dto.getPassword()));

        // Set sensitive fields explicitly with secure defaults
        user.setRole("USER");
        user.setIsAdmin(false);
        user.setAccountBalance(0.0);

        User savedUser = userRepository.save(user);
        return ResponseEntity.ok(savedUser);
    }
}

// Even if attacker sends extra fields, they are ignored:
// POST /api/register
// {
//   "username": "attacker",
//   "email": "attacker@evil.com",
//   "password": "pass123",
//   "role": "ADMIN",          // IGNORED
//   "isAdmin": true,          // IGNORED
//   "accountBalance": 1000000 // IGNORED
// }
//
// Result: Regular user account with default privileges

Types of Mass Assignment

Privilege Escalation via Role Fields

The most common and dangerous variant. Attackers add fields like role=admin, isAdmin=true, permissions=["*"], or accessLevel=99 to gain unauthorized administrative access. This can grant them the ability to view all data, modify system settings, create other admin accounts, or completely take over the application. Even boolean flags like isVerified or isPremium can be exploited to bypass payment gates or unlock premium features.

Financial Manipulation

Attackers modify financial fields to gain monetary advantage. Common targets include price, discount, balance, creditLimit, or loyaltyPoints. An e-commerce application might allow users to set product.price=0.01 during checkout, or a banking API might let attackers set accountBalance=1000000 during registration. Even fields like shippingCost or taxRate can be exploited to reduce total costs.

Account Takeover

Attackers overwrite authentication-related fields to hijack accounts. This includes modifying email, phoneNumber, or recoveryEmail to take control of password reset flows, setting passwordResetToken to a known value, or modifying linkedAccounts to associate their account with someone else's OAuth profile. In some cases, attackers can even modify userId or accountId fields to overwrite data belonging to other users.

Impact

A successful Mass Assignment attack can have severe consequences for an organization. The impact varies depending on which fields are exposed, but can range from privilege escalation to complete system compromise.

Unauthorized privilege escalation

Attackers gain administrative access by setting role or permission fields during registration or profile updates. This grants them unrestricted access to sensitive data, administrative functions, and the ability to create additional compromised accounts.

Financial fraud and theft

Manipulation of price, balance, or discount fields can lead to direct financial loss. E-commerce platforms may suffer from zero-dollar purchases, banking applications may allow attackers to inflate their balances, and subscription services may be accessed without payment.

Account takeover

By modifying email addresses, recovery methods, or authentication tokens, attackers can hijack existing user accounts, including those belonging to administrators or high-value targets. This can lead to identity theft, data breaches, and reputational damage.

Data integrity compromise

Attackers can modify internal system fields like timestamps, audit logs, foreign keys, or status flags, corrupting the integrity of business data. This can disrupt operations, invalidate regulatory compliance, and make forensic investigation extremely difficult.

Prevention Checklist

Use DTOs (Data Transfer Objects) for all user input

Create dedicated DTO classes that contain ONLY the fields users should be allowed to modify. Never bind request data directly to domain entities or database models. Map DTO fields to entity properties explicitly in your controller or service layer. This is the most effective defense against mass assignment.

Implement allowlists, never denylists

Explicitly define which fields can be modified through allowlists (permit lists). Do not rely on denylists (blocking specific fields) as they are easy to bypass and difficult to maintain. Use framework features like Rails' permit(), Django's fields in serializers, or create custom validation schemas.

Use @JsonIgnore or equivalent annotations

Mark sensitive fields with annotations like @JsonIgnore in Java, @Exclude in Python, or hidden: true in Node.js serializers to prevent them from being populated during deserialization. This provides an additional layer of protection even if DTOs are not used everywhere.

Validate input against expected schema

Implement strict input validation using schema validation libraries like JSON Schema, Joi, Zod, or Pydantic. Reject requests that contain unexpected fields rather than silently ignoring them. This helps detect potential attacks and makes debugging easier.

Write integration tests for mass assignment

Create automated tests that attempt to set sensitive fields through API requests. Ensure that fields like isAdmin, role, balance, and other privileged properties cannot be modified by regular users. Include these tests in your CI/CD pipeline to catch regressions.

Enable API schema validation

Use OpenAPI/Swagger specifications to define strict request schemas and enable server-side validation. Tools like OpenAPI validators, API gateways, or middleware can automatically reject requests that do not conform to the schema. This centralizes validation logic and reduces the chance of developer error.

Real-World Examples

2012

GitHub Public Key Exploit

A security researcher discovered a mass assignment vulnerability in GitHub's Ruby on Rails application that allowed adding SSH public keys to any repository. By sending a specially crafted request with an additional public_key[user_id] parameter, attackers could associate their SSH key with any user's account, including the Rails project itself. GitHub patched the vulnerability within hours of disclosure.

2015

Shopify Admin Escalation

Security researchers reported a mass assignment vulnerability in Shopify's partner API that allowed privilege escalation. By including hidden parameters in partner registration requests, attackers could set their account's permission level to admin, granting unauthorized access to store management functions and customer data. The vulnerability was fixed following responsible disclosure.

2018

HackerOne Platform Vulnerabilities

Multiple mass assignment vulnerabilities have been reported on bug bounty platforms like HackerOne across various companies. Common findings include the ability to modify bounty_amount, is_verified, or role fields by including extra parameters in API requests. These reports consistently rank among the highest-paid bounties, with rewards reaching $10,000+ for critical findings.

2020

E-commerce Price Manipulation

Several major e-commerce platforms were found vulnerable to mass assignment in their checkout flows. Attackers could modify product.price, discount_percentage, or total_amount fields during checkout, purchasing expensive items for pennies. One incident involved luxury goods worth $50,000+ being sold for under $100 before the vulnerability was discovered during fraud analysis.

Ready to Test Your Knowledge?

Put what you have learned into practice. Try identifying and fixing Mass Assignment vulnerabilities in our interactive coding challenges, or explore more security guides to deepen your understanding.