Files
Anthropic-Cybersecurity-Skills/skills/performing-api-rate-limiting-bypass/scripts/agent.py
T
mukul975 c21af3347e Complete folder anatomy for all 649 cybersecurity skills + update LICENSE to Mahipal
- Add scripts/agent.py and references/api-reference.md to all remaining skills
- Update all 648 LICENSE files: copyright now reads 'Mahipal'
- Add implementing-security-monitoring-with-datadog (new skill with full anatomy)
- All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
2026-03-11 00:22:12 +01:00

264 lines
8.8 KiB
Python

#!/usr/bin/env python3
# For authorized testing only
"""API rate limiting bypass testing agent."""
import json
import sys
import argparse
import time
from datetime import datetime
try:
import requests
except ImportError:
print("Install: pip install requests")
sys.exit(1)
BYPASS_HEADERS = [
{"X-Forwarded-For": "127.0.0.1"},
{"X-Forwarded-For": "10.0.0.1"},
{"X-Real-IP": "127.0.0.1"},
{"X-Originating-IP": "127.0.0.1"},
{"X-Client-IP": "192.168.1.1"},
{"X-Forwarded-Host": "localhost"},
{"True-Client-IP": "127.0.0.1"},
{"CF-Connecting-IP": "127.0.0.1"},
{"X-Custom-IP-Authorization": "127.0.0.1"},
{"Forwarded": "for=127.0.0.1"},
]
def detect_rate_limit_headers(url, auth_header=None):
"""Send initial request and extract rate limit response headers."""
headers = {"User-Agent": "RateLimit-Tester/1.0"}
if auth_header:
headers["Authorization"] = auth_header
try:
resp = requests.get(url, headers=headers, timeout=10)
rate_headers = {}
for key in resp.headers:
lower = key.lower()
if any(rl in lower for rl in ["ratelimit", "rate-limit", "x-rate",
"retry-after", "x-ratelimit"]):
rate_headers[key] = resp.headers[key]
return {
"url": url,
"status": resp.status_code,
"rate_limit_headers": rate_headers,
"has_rate_limiting": len(rate_headers) > 0,
}
except Exception as e:
return {"url": url, "error": str(e)}
def test_header_bypass(url, auth_header=None, request_count=30):
"""Test rate limit bypass via IP spoofing headers."""
findings = []
base_headers = {"User-Agent": "RateLimit-Tester/1.0"}
if auth_header:
base_headers["Authorization"] = auth_header
for i in range(request_count):
try:
resp = requests.get(url, headers=base_headers, timeout=5)
if resp.status_code == 429:
baseline_hit = i + 1
break
except Exception:
pass
else:
findings.append({
"test": "baseline",
"issue": f"No rate limit hit after {request_count} requests",
"severity": "HIGH",
})
return findings
for bypass in BYPASS_HEADERS:
test_headers = {**base_headers, **bypass}
header_name = list(bypass.keys())[0]
success_count = 0
for i in range(10):
bypass[header_name] = f"10.{i}.{i}.{i}"
test_headers = {**base_headers, **bypass}
try:
resp = requests.get(url, headers=test_headers, timeout=5)
if resp.status_code != 429:
success_count += 1
except Exception:
pass
if success_count > 5:
findings.append({
"test": "header_bypass",
"header": header_name,
"issue": f"Rate limit bypassed using {header_name} header ({success_count}/10 successful)",
"severity": "HIGH",
})
return findings
def test_method_bypass(url, auth_header=None):
"""Test if rate limiting applies across HTTP methods."""
methods = ["GET", "POST", "PUT", "PATCH", "HEAD", "OPTIONS"]
findings = []
headers = {"User-Agent": "RateLimit-Tester/1.0"}
if auth_header:
headers["Authorization"] = auth_header
method_results = {}
for method in methods:
try:
resp = requests.request(method, url, headers=headers, timeout=5)
method_results[method] = resp.status_code
except Exception:
method_results[method] = "error"
rate_limited = [m for m, s in method_results.items() if s == 429]
not_limited = [m for m, s in method_results.items() if isinstance(s, int) and s != 429]
if rate_limited and not_limited:
findings.append({
"test": "method_bypass",
"rate_limited": rate_limited,
"not_limited": not_limited,
"issue": f"Rate limit not applied to methods: {', '.join(not_limited)}",
"severity": "MEDIUM",
})
return findings
def test_path_bypass(url, auth_header=None):
"""Test rate limit bypass via URL path manipulation."""
from urllib.parse import urlparse
parsed = urlparse(url)
path = parsed.path
path_variations = [
path + "/",
path + "?",
path + "#",
path.upper(),
path + "%20",
path + ";",
path.replace("/", "//"),
path + "/.",
path + "/..",
]
findings = []
headers = {"User-Agent": "RateLimit-Tester/1.0"}
if auth_header:
headers["Authorization"] = auth_header
for variant in path_variations:
test_url = f"{parsed.scheme}://{parsed.netloc}{variant}"
try:
resp = requests.get(test_url, headers=headers, timeout=5, allow_redirects=False)
if resp.status_code not in (429, 404, 301, 302):
findings.append({
"test": "path_bypass",
"original": path,
"variant": variant,
"status": resp.status_code,
"issue": f"Path variation '{variant}' bypasses rate limit (status {resp.status_code})",
"severity": "MEDIUM",
})
except Exception:
pass
return findings
def test_encoding_bypass(url, auth_header=None):
"""Test rate limit bypass via parameter encoding variations."""
from urllib.parse import urlparse, parse_qs, urlencode
parsed = urlparse(url)
params = parse_qs(parsed.query)
findings = []
headers = {"User-Agent": "RateLimit-Tester/1.0"}
if auth_header:
headers["Authorization"] = auth_header
null_byte_url = url + "%00"
try:
resp = requests.get(null_byte_url, headers=headers, timeout=5)
if resp.status_code != 429:
findings.append({
"test": "null_byte_bypass",
"status": resp.status_code,
"issue": "Null byte appended bypasses rate limit",
"severity": "HIGH",
})
except Exception:
pass
return findings
def run_audit(args):
"""Execute API rate limiting bypass audit."""
print(f"\n{'='*60}")
print(f" API RATE LIMITING BYPASS TESTING")
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
print(f"{'='*60}\n")
report = {}
all_findings = []
detection = detect_rate_limit_headers(args.url, args.auth)
report["rate_limit_detection"] = detection
print(f"--- RATE LIMIT DETECTION ---")
print(f" URL: {detection.get('url','')}")
print(f" Has Rate Limiting: {detection.get('has_rate_limiting', False)}")
for k, v in detection.get("rate_limit_headers", {}).items():
print(f" {k}: {v}")
if args.test_headers:
header_findings = test_header_bypass(args.url, args.auth, args.request_count)
all_findings.extend(header_findings)
print(f"\n--- HEADER BYPASS ({len(header_findings)} findings) ---")
for f in header_findings:
print(f" [{f['severity']}] {f['issue']}")
if args.test_methods:
method_findings = test_method_bypass(args.url, args.auth)
all_findings.extend(method_findings)
print(f"\n--- METHOD BYPASS ({len(method_findings)} findings) ---")
for f in method_findings:
print(f" [{f['severity']}] {f['issue']}")
if args.test_paths:
path_findings = test_path_bypass(args.url, args.auth)
all_findings.extend(path_findings)
print(f"\n--- PATH BYPASS ({len(path_findings)} findings) ---")
for f in path_findings:
print(f" [{f['severity']}] {f['issue']}")
report["findings"] = all_findings
report["total_findings"] = len(all_findings)
return report
def main():
parser = argparse.ArgumentParser(description="API Rate Limiting Bypass Tester")
parser.add_argument("--url", required=True, help="Target API endpoint URL")
parser.add_argument("--auth", help="Authorization header value")
parser.add_argument("--request-count", type=int, default=30,
help="Requests for baseline detection (default: 30)")
parser.add_argument("--test-headers", action="store_true", help="Test header-based bypasses")
parser.add_argument("--test-methods", action="store_true", help="Test HTTP method bypasses")
parser.add_argument("--test-paths", action="store_true", help="Test URL path bypasses")
parser.add_argument("--output", help="Save report to JSON file")
args = parser.parse_args()
report = run_audit(args)
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"\n[+] Report saved to {args.output}")
if __name__ == "__main__":
main()