6.1 KiB
6.1 KiB
name, description
| name | description |
|---|---|
| mass-assignment | Mass assignment testing for unauthorized field binding and privilege escalation via API parameters |
Mass Assignment
Mass assignment binds client-supplied fields directly into models/DTOs without field-level allowlists. It commonly leads to privilege escalation, ownership changes, and unauthorized state transitions in modern APIs and GraphQL.
Attack Surface
- REST/JSON, GraphQL inputs, form-encoded and multipart bodies
- Model binding in controllers/resolvers; ORM create/update helpers
- Writable nested relations, sparse/patch updates, bulk endpoints
Reconnaissance
Surface Map
- Controllers with automatic binding (e.g., request.json → model)
- GraphQL input types mirroring models; admin/staff tools exposed via API
- OpenAPI/GraphQL schemas: uncover hidden fields or enums
- Client bundles and mobile apps: inspect forms and mutation payloads for field names
Parameter Strategies
- Flat fields:
isAdmin,role,roles[],permissions[],status,plan,tier,premium,verified,emailVerified - Ownership/tenancy:
userId,ownerId,accountId,organizationId,tenantId,workspaceId - Limits/quotas:
usageLimit,seatCount,maxProjects,creditBalance - Feature flags/gates:
features,flags,betaAccess,allowImpersonation - Billing:
price,amount,currency,prorate,nextInvoice,trialEnd
Shape Variants
- Alternate shapes: arrays vs scalars; nested JSON; objects under unexpected keys
- Dot/bracket paths:
profile.role,profile[role],settings[roles][] - Duplicate keys and precedence:
{"role":"user","role":"admin"} - Sparse/patch formats: JSON Patch/JSON Merge Patch; try adding forbidden paths
Encodings and Channels
- Content-types:
application/json,application/x-www-form-urlencoded,multipart/form-data,text/plain - GraphQL: add suspicious fields to input objects; overfetch response to detect changes
- Batch/bulk: arrays of objects; verify per-item allowlists not skipped
Key Vulnerabilities
Privilege Escalation
- Set role/isAdmin/permissions during signup/profile update
- Toggle admin/staff flags where exposed
Ownership Takeover
- Change ownerId/accountId/tenantId to seize resources
- Move objects across users/tenants
Feature Gate Bypass
- Enable premium/beta/feature flags via flags/features fields
- Raise limits/seatCount/quotas
Billing and Entitlements
- Modify plan/price/prorate/trialEnd or creditBalance
- Bypass server recomputation
Nested and Relation Writes
- Writable nested serializers or ORM relations allow creating or linking related objects beyond caller's scope
Advanced Techniques
GraphQL Specific
- Field-level authz missing on input types: attempt forbidden fields in mutation inputs
- Combine with aliasing/batching to compare effects
- Use fragments to overfetch changed fields immediately after mutation
ORM Framework Edges
- Rails: strong parameters misconfig or deep nesting via
accepts_nested_attributes_for - Laravel: $fillable/$guarded misuses;
guarded=[]opens all; casts mutating hidden fields - Django REST Framework: writable nested serializer, read_only/extra_kwargs gaps, partial updates
- Mongoose/Prisma: schema paths not filtered;
select:falsedoesn't prevent writes; upsert defaults
Parser and Validator Gaps
- Validators run post-bind and do not cover extra fields
- Unknown fields silently dropped in response but persisted underneath
- Inconsistent allowlists between mobile/web/gateway; alt encodings bypass validation pipeline
Bypass Techniques
Content-Type Switching
- Switch JSON ↔ form-encoded ↔ multipart ↔ text/plain; some code paths only validate one
Key Path Variants
- Dot/bracket/object re-shaping to reach nested fields through different binders
Batch Paths
- Per-item checks skipped in bulk operations
- Insert a single malicious object within a large batch
Race and Reorder
- Race two updates: first sets forbidden field, second normalizes
- Final state may retain forbidden change
Testing Methodology
- Identify endpoints - Create/update endpoints and GraphQL mutations
- Capture responses - Observe returned fields to build candidate list
- Build sensitive-field dictionary - Per resource: role, isAdmin, ownerId, status, plan, limits, flags
- Inject candidates - Alongside legitimate updates across transports and encodings
- Compare state - Before/after diffs across roles
- Test variations - Nested objects, arrays, alternative shapes, duplicate keys, batch operations
Validation
- Show a minimal request where adding a sensitive field changes persisted state for a non-privileged caller
- Provide before/after evidence (response body, subsequent GET, or GraphQL query) proving the forbidden attribute value
- Demonstrate consistency across at least two encodings or channels
- For nested/bulk, show that protected fields are written within child objects or array elements
- Quantify impact (e.g., role flip, cross-tenant move, quota increase) and reproducibility
False Positives
- Server recomputes derived fields (plan/price/role) ignoring client input
- Fields marked read-only and enforced consistently across encodings
- Only UI-side changes with no persisted effect
Impact
- Privilege escalation and admin feature access
- Cross-tenant or cross-account resource takeover
- Financial/billing manipulation and quota abuse
- Policy/approval bypass by toggling verification or status flags
Pro Tips
- Build a sensitive-field dictionary per resource and fuzz systematically
- Always try alternate shapes and encodings; many validators are shape/CT-specific
- For GraphQL, diff the resource immediately after mutation; effects are often visible even if the mutation returns filtered fields
- Inspect SDKs/mobile apps for hidden field names and nested write examples
- Prefer minimal PoCs that prove durable state changes; avoid UI-only effects
Summary
Mass assignment is eliminated by explicit mapping and per-field authorization. Treat every client-supplied attribute—especially nested or batch inputs—as untrusted until validated against an allowlist and caller scope.