first commit
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
---
|
||||
name: mass-assignment
|
||||
description: 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:false` doesn'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
|
||||
|
||||
1. **Identify endpoints** - Create/update endpoints and GraphQL mutations
|
||||
2. **Capture responses** - Observe returned fields to build candidate list
|
||||
3. **Build sensitive-field dictionary** - Per resource: role, isAdmin, ownerId, status, plan, limits, flags
|
||||
4. **Inject candidates** - Alongside legitimate updates across transports and encodings
|
||||
5. **Compare state** - Before/after diffs across roles
|
||||
6. **Test variations** - Nested objects, arrays, alternative shapes, duplicate keys, batch operations
|
||||
|
||||
## Validation
|
||||
|
||||
1. Show a minimal request where adding a sensitive field changes persisted state for a non-privileged caller
|
||||
2. Provide before/after evidence (response body, subsequent GET, or GraphQL query) proving the forbidden attribute value
|
||||
3. Demonstrate consistency across at least two encodings or channels
|
||||
4. For nested/bulk, show that protected fields are written within child objects or array elements
|
||||
5. 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
|
||||
|
||||
1. Build a sensitive-field dictionary per resource and fuzz systematically
|
||||
2. Always try alternate shapes and encodings; many validators are shape/CT-specific
|
||||
3. For GraphQL, diff the resource immediately after mutation; effects are often visible even if the mutation returns filtered fields
|
||||
4. Inspect SDKs/mobile apps for hidden field names and nested write examples
|
||||
5. 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.
|
||||
Reference in New Issue
Block a user