Client-side + Server-side + Gadget-aware + WAF-evasive + DoS + Sustained Assault
PPHunter is a professional security research tool that finds, confirms, and weaponizes prototype pollution vulnerabilities across the full stack — from client-side JavaScript heap pollution to server-side Node.js/PHP/Python injection, through gadget chains, sanitizer bypasses, and (when authorized) sustained denial-of-service.
pip install -r requirements.txt --break-system-packages
playwright install chromiumRequires Python 3.10+ and ANTHROPIC_API_KEY set in environment for AI analysis features.
python -m pphunter "https://target.example.com/"Runs: crawl → WAF fingerprint → library detection → CSPP → SSPP → CORS → JWT → DOM-XSS → gadget matching → PoC synthesis → AI analysis → HTML/MD/JSON report.
python -m pphunter "https://target.example.com/" --modules csppModules: cspp, sspp, gadgets, xss, poc, or all (default).
python -m pphunter "https://target.example.com/" --dosActively exploits prototype pollution to cause denial-of-service conditions against discovered endpoints.
python -m pphunter "https://target.example.com/" --sustain --sustain-workers 10 --sustain-duration 60Auto-detects backend, runs escalating assault phases until server is crashed or sustained DoS is achieved. See Sustained Assault Mode for full details.
python -m pphunter "https://target.example.com/" --smoke| Flag | Description |
|---|---|
target |
Target URL (positional, required for scan mode) |
--scope |
Allowed hosts/CIDRs. Inferred from target's registered domain if omitted |
--modules |
cspp, sspp, gadgets, xss, poc, or all (default) |
--output |
Output base path (default: ./pphunter_report_TIMESTAMP) |
--format |
json, md, html, or all (default) |
--timeout |
Navigation timeout in ms (default: 30000) |
--rate |
Requests per second for rate limiting (default: 2.0, min: 0.1) |
--stealth |
Stealth mode: 0.5 rps, jitter, UA rotation, browser-like headers |
--smoke |
Passive checks only — no injection, no payloads sent |
--wayback |
Query Wayback Machine for historical endpoints |
--graphql |
Enable GraphQL schema reconstruction (auto-runs when GraphQL detected) |
--oob |
Enable OOB DNS callback via local mock (for --oob-server production, see below) |
--oob-server |
Interactsh server URL for production OOB (e.g. https://oast.pro) |
--oob-token |
Interactsh authentication token |
--auth |
Auth mode: cookie, bearer, or form |
--auth-value |
Cookie string or Bearer token value |
--auth-login-url |
Login URL for form-based auth |
--auth-username-selector |
CSS selector for username field |
--auth-password-selector |
CSS selector for password field |
--auth-submit-selector |
CSS selector for submit button |
--auth-username |
Username for form auth |
--auth-password |
Password for form auth |
--dos |
Run DoS exploitation module (stress testing — explicit authorization required) |
--sustain |
Run full sustained crash assault (explicit authorization required) |
--sustain-workers |
Parallel workers for Phase 2+ (default: 10) |
--sustain-duration |
Duration in seconds for assault phases (default: 30) |
--analyze |
Enable AI interpretation via Claude (requires ANTHROPIC_API_KEY) |
--session-id |
Save/resume scan session by ID |
--list-sessions |
List all saved sessions |
--delete-session |
Delete a saved session |
--no-bundle |
Disable disclosure ZIP bundling |
--diff |
Compare two scan reports |
PPHunter runs in four stages across six independent capability areas:
graph TD
classDef stage fill:#2e3440,stroke:#88c0d0,stroke-width:2px,color:#eceff4,border-radius:5px;
classDef module fill:#3b4252,stroke:#5e81ac,stroke-width:1px,color:#d8dee9;
subgraph Stage1[Stage 1: Reconnaissance]
C[Crawler]:::module
W[WAF Fingerprinting]:::module
L[Library Intel]:::module
end
subgraph Stage2[Stage 2: Detection]
CSPP[Client-Side PP & XSS]:::module
SSPP[Server-Side PP]:::module
end
subgraph Stage3[Stage 3: Confirmation]
GM[Gadget Matching]:::module
OOB[OOB Callback]:::module
end
subgraph Stage4[Stage 4: Reporting]
PoC[PoC Synthesis]:::module
AI[AI Interpretation]:::module
end
Stage1 --> Stage2
Stage2 --> Stage3
Stage3 --> Stage4
class Stage1,Stage2,Stage3,Stage4 stage;
Crawler (crawler.py)
- Headless Chromium (Playwright) crawls the target, collecting: all URLs, JSON endpoints, JavaScript files, URL parameters, form inputs, and postMessage listeners.
- Establishes a prototype pollution baseline by snapshotting
Object.prototypekeys before any payload is injected.
WAF Fingerprinting (waf_fingerprinter.py)
- Analyzes HTTP response headers and body to identify the WAF vendor: Cloudflare, AWS WAF, Azure WAF, Google Cloud Armor, ModSecurity, Imperva, Akamai, or F5 BIG-IP.
- Fingerprints the backend framework: Express, Flask, Laravel, FastAPI, Spring Boot, Django, Rails, Gin.
- Probes content-type acceptance (JSON, multipart, XML, form-urlencoded, plain text).
- Sets
recommended_bypass_categoryper WAF vendor — guides the bypass engine's mutation strategy ranking.
Library Intelligence (libintel.py)
- Matches detected JavaScript libraries against an embedded CVE database covering 40+ libraries (jQuery, lodash, Handlebars, React, Moment.js, Chart.js, Vue, and more).
- Returns: CVE ID, severity (critical/high/medium/low), vulnerability class (XSS, PROTOTYPE_POLLUTION, RCE, REDOS, SSRF, AUTH_BYPASS), and description.
- Also detects sanitizer libraries (DOMPurify, sanitize-html) for sanitizer bypass analysis.
Endpoint Classification (endpoint_classifier.py)
- Classifies every discovered endpoint as: JSON API, HTML page, or static asset.
- Identifies sensitive endpoints (auth, admin, payment, API) regardless of content type.
- Extracts top-level JSON keys so SSPP detection knows exactly what response fields to probe.
GraphQL Schema Reconstruction (graphql_recon.py)
- Auto-runs when GraphQL is detected. Introspects the full schema, enumerates all queries/mutations/subscriptions, and identifies high-value operations for targeted testing.
CORS Misconfiguration Scan (cors_scanner.py)
- Tests all discovered JSON endpoints against foreign origins (evil.com, attacker.example.com, null).
- Detects: unrestricted
Access-Control-Allow-Origin, credentials + wildcard origin, missingAccess-Control-Allow-Methodsrestrictions.
JWT Analysis (jwt_analyzer.py)
- Extracts JWT tokens from responses, cookies, and localStorage.
- Decodes and analyzes algorithm (
none,HS256,RS256, etc.), expiry, and payload contents. - Detects: algorithm confusion attacks, missing expiry, weak symmetric keys, and token leakage patterns.
WebSocket Surface Detection (websocket_surface.py)
- Detects WebSocket connections in JavaScript code and tests them for prototype pollution via WS frame injection.
Client-Side Prototype Pollution (cspp_detector.py)
- Uses headless Chromium. Takes a heap baseline snapshot of
Object.prototype, injects payloads through URL hash parameters and postMessage, then takes a second heap snapshot. - Uses heap diffing — any new key appearing in
Object.prototypeafter injection = confirmed CSPP. - Tests 4 payload tiers:
- Tier 1 (canonical):
__proto__[key]=value,constructor[prototype][key]=value - Tier 2 (encoded): URL-encoded variants, parameter pollution combos
- Tier 3 (JSON):
{"__proto__": {"key": value}} - Tier 4 (depth):
__proto__.__proto__[key]=value
- Tier 1 (canonical):
Server-Side Prototype Pollution (sspp_detector.py)
- Probes JSON API endpoints with three black-box detection techniques — no code execution required:
- JSON spaces: Injects
{"__proto__": {"json spaces": 10}}→ if follow-up responses are indented, server is vulnerable (parsers that mergeObject.prototypeapply the spacing). - Charset override: Injects
{"__proto__": {"content-type": "application/json; charset=utf-7"}}→ if follow-up Content-Type header changes to utf-7, confirmed. - Status code override: Injects
{"__proto__": {"status": 555}}→ if follow-up returns 555, confirmed.
- JSON spaces: Injects
- All three techniques are non-destructive and include automatic cleanup payloads.
- WAF bypass is automatic — if any request is blocked (403/406), the WAF Bypass Engine takes over and finds a working structural mutation before retrying.
DOM-Based XSS (dom_xss_detector.py)
- After CSPP is confirmed and gadgets are matched, tests confirmed gadget chains in a real Chromium DOM context.
- Uses known sink patterns:
innerHTML,outerHTML,document.write,eval,setTimeout,setInterval,location,href,src,formaction.
Gadget Matching (gadget_matcher.py)
- Takes confirmed library + version and queries the gadget database (60+ gadgets across jQuery, lodash, Handlebars, Mongoose, Express, etc.).
- Each gadget has:
gadget_id,CVSS score,impact(XSS/RCE/AUTHBYPASS/DOS),payload template,sink function. - Matches are ranked by CVSS and passed to the PoC synthesizer.
Sanitizer Bypass Detection (sanitizer_bypass.py)
- Detects DOMPurify and sanitize-html in JavaScript bundles.
- Checks detected version against known bypass CVEs (e.g. DOMPurify bypass via
xlink:href,styletag mutation). - Confirmed bypasses are reported alongside the base CSPP finding.
OOB Callback Confirmation (oob_handler.py)
- When
--oobis set, runs a local mock interactsh server for DNS callbacks. - When
--oob-serveris set, uses a production Interactsh server (oast.pro or self-hosted). - Used to confirm RCE viability: if the server-side payload can trigger an OOB DNS lookup to your server, remote code execution is viable (not proof-of-concept RCE — just a viability probe).
PoC Synthesis (poc_synthesizer.py)
- Generates submission-ready proof-of-concept packages per confirmed gadget chain.
- Output formats: curl command, fetch call, HTML exploit page, or full automated exploit script.
- All PoCs are WAF-encoded using the confirmed bypass strategy.
- Includes CVSS 3.1 vector, severity label, and remediation recommendation.
AI Interpretation (ai_layer.py)
- When
--analyzeis set andANTHROPIC_API_KEYis in the environment, PPHunter sends the full structured report to Claude for natural language interpretation. - Output includes: executive summary, critical risks, recommended remediation steps, and chained attack paths.
- Falls back to
[AI analysis unavailable — set ANTHROPIC_API_KEY to enable]if no key is found.
Disclosure Bundling (evidence_bundler.py)
- Automatically bundles: JSON report, Markdown summary, HTML report, and PoC files into a timestamped ZIP archive.
- Disabled with
--no-bundle.
Report Diffing (diff_scanner.py)
python -m pphunter --diff old_report.json new_report.jsonShows: new/resolved CSPP findings, library version changes (with regression flag), new gadget chains, and delta severity.
PPHunter's WAF bypass system is built on WAFFLED (ACSAC 2025) research — 1,207 confirmed bypasses across Cloudflare, AWS WAF, Azure WAF, Google Cloud Armor, and ModSecurity.
The bypass engine runs a 4-step pipeline for every blocked request:
sequenceDiagram
participant P as PPHunter
participant M as Mutator Engine
participant W as WAF
participant B as Target Backend
P->>W: Initial Injection Probe
W-->>P: 403 Forbidden / 406 Not Acceptable
P->>M: Request Bypass Strategy
Note over M: Generate 12 Structural Mutations
M-->>P: Ranked Strategies (by WAF Vendor)
loop Bypass Validation Pipeline
P->>W: Send Mutated Request
alt Blocked
W-->>P: 403 / 406
else Bypassed
W->>B: Mutated Request Pass-through
B-->>P: 200 OK / Target Response
Note over P: Lock in successful strategy
end
end
- Fingerprint —
WAFFingerprinteridentifies WAF vendor and backend framework (1-3 probe requests). - Mutate —
StructuralMutatorgenerates 12 distinct structural mutations that change how the request is encoded without changing the payload content. - Rank —
BypassSelectororders mutations by likelihood of success against the detected WAF. - Validate —
BypassValidatorsends mutations live until one produces a non-blocked (non-403/406) response.
| Strategy | Technique | Best Against |
|---|---|---|
| JSON-01 | Null byte in JSON key ("__pro\x00to__") |
Generic WAFs |
| JSON-02 | Duplicate JSON key (WAF uses first, backend uses last) | Cloudflare, AWS WAF |
| JSON-03 | Gzip-compressed JSON body | ModSecurity |
| JSON-04 | JSON key with Unicode normalization (\u005f = _) |
Cloudflare |
| STRUCT-01 | Multipart/form-data with JSON inside form field | Cloudflare, AWS WAF |
| STRUCT-02 | application/xml content type | Azure WAF, Imperva |
| STRUCT-03 | application/x-www-form-urlencoded | Akamai |
| STRUCT-04 | Null byte in header name | Generic WAFs |
| STRUCT-05 | HTTP method override via _method parameter |
Generic |
| STRUCT-06 | Phantom Version cookie (PHP/laravel) |
Cloudflare |
| STRUCT-07 | UTF-7 charset in Content-Type | Azure WAF |
| STRUCT-08 | Charset x-user-defined (allows raw bytes) |
Google Cloud Armor |
When PPHunter finds a working strategy, all subsequent requests in that scan session use it automatically — no manual configuration needed.
The DoS module actively exploits prototype pollution to create denial-of-service conditions. It requires --dos to be explicitly set and only runs against explicitly authorized targets.
| Technique | Vector | Severity | Backend |
|---|---|---|---|
eval_injection |
process.exit(1) via eval PP |
crash | Node.js |
unhandled_exception |
Unhandled exception getter chain | crash | Node.js |
reference_error |
Cascading ReferenceError chain | crash | Node.js |
type_confusion |
Number used as function call | crash | Node.js |
memory_exhaustion |
10MB string injected into prototype | memory | All |
infinite_recursion |
Self-calling function in prototype | crash | Node.js |
cpu_spin |
Tight CPU loop in prototype getter | degradation | Node.js |
json_bomb |
100K-level deeply nested JSON | degradation | All |
redos |
Catastrophic regex backtracking injected via PP | degradation | All |
pool_exhaust |
Slow trickle body holds worker for 120s | degradation | PHP, Python, Node |
All techniques include automatic cleanup payloads (setting the injected key to null). The module reports: severity (crash/degradation/memory/none), response time, whether cleanup failed (sustained=true).
Each technique uses the WAF Bypass Engine — if a request is blocked, PPHunter automatically finds a working bypass and retries before declaring a technique ineffective.
The --sustain flag runs the full autonomous crash assault. It auto-detects the backend, runs reconnaissance, tests escalating DoS phases, and verifies whether the server remains down after the attack stops.
WARNING: This mode is for authorized stress testing only. Do not run against targets you do not have explicit written permission to test.
stateDiagram-v2
[*] --> Phase0: Reconnaissance
Phase0 --> Phase1: Fingerprint & Detect
state Phase1 {
[*] --> SequentialSweep: Send DoS Techniques
}
Phase1 --> Phase2: Server still up
state Phase2 {
[*] --> RotatingPool: N workers (Trickle/Chunked)
}
Phase2 --> Phase3: Server still up
state Phase3 {
[*] --> EscalatedPool: 2N workers (1.6x waves)
}
Phase3 --> Phase4: Server still up
state Phase4 {
[*] --> MultiAssault: All techniques in tight loop
}
Phase4 --> Verification: Assault complete
Verification --> [*]: Sustained Crash Confirmed
The sustain orchestrator runs 4 phases:
Phase 0 — Reconnaissance
- Crawls target, discovers JSON endpoints
- Fingerprints WAF vendor and backend framework
- Runs library intelligence and CSPP/SSPP detection
- Results feed into Phases 1-4
Phase 1 — Sequential Sweep
- Sends each of the 10 DoS techniques sequentially (3 rounds each)
- Best technique is selected by severity (crash > degradation > memory)
- All requests use WAF bypass automatically
Phase 2 — Rotating Pool Exhaustion (if server still up)
- Sends
Nslow-trickle requests simultaneously, whereN = --sustain-workers(default: 10) - Each request holds a worker busy for 120 seconds by streaming 120KB at 1KB/s using true chunked transfer encoding (no
Content-Lengthheader — forcesTransfer-Encoding: chunkedso the server reads chunk-by-chunk and blocks between reads) - Wave 2 fires every 60 seconds via fire-and-forget
asyncio.create_task()— waves genuinely overlap, keeping the pool perpetually saturated - Total duration:
waves × rotate_everyseconds (e.g., 5 waves × 60s = 300s with default--sustain-duration 30)
Phase 3 — Escalated Pool Exhaustion (if server still up)
- Same as Phase 2 but with
N = --sustain-workers × 2andwaves × 1.6× - Brings in fresh worker saturation if Phase 2 degraded but didn't crash
Phase 4 — Combined Multi-Technique Assault (if server still up)
Nparallel workers (default: 25), each running all effective techniques in a tight loop- Runs for
--sustain-duration × 2seconds (default: 60s) - Uses a
while time.time() < deadlineloop so workers genuinely sustain for the full duration
Verification
- 5 health checks at 2-second intervals after all assault phases end
- If server returns HTTP 200 on 3+ checks = recovered (temporary degradation)
- If server fails 3+ checks = sustained crash confirmed
| Flag | Effect |
|---|---|
--sustain-workers 10 |
Phase 2: 10 workers per wave; Phase 3: 20; Phase 4: 25 |
--sustain-duration 60 |
Phase 2: 60/60 = 1 wave; Phase 3: 120/60 = 2 waves; Phase 4: 120s |
PPHunter detects the backend from response headers and error pages:
| Backend | Signatures | Pool Size Default |
|---|---|---|
| PHP/Laravel | X-Powered-By: PHP, laravel_session cookie |
10 |
| Node.js/Express | x-powered-by: express, Cannot GET errors |
4 |
| Python/Flask | server: werkzeug |
4 |
| Python/FastAPI | server: uvicorn |
4 |
| Java/Spring | x-application-context header |
20 |
# Save a scan session
python -m pphunter "https://target.example.com/" --session-id my_scan_001
# Resume a saved session
python -m pphunter "https://target.example.com/" --session-id my_scan_001
# List all saved sessions
python -m pphunter --list-sessions
# Delete a saved session
python -m pphunter --delete-session my_scan_001PPHunter includes a configurable rate limiter (rate_limiter.py):
RateLimitConfig(
requests_per_second=2.0, # default
jitter_ms=200, # ± random jitter
stealth_mode=False, # 0.5 rps, 500-2000ms jitter, UA rotation
user_agent_rotation=False,
burst_limit=5,
)Stealth mode (--stealth):
- Reduces to 0.5 requests/second
- Adds 500-2000ms jitter between requests
- Rotates User-Agent across a curated list of real browser UAs (Chrome/Firefox/Safari/Linux)
- Injects realistic browser headers:
Accept,Accept-Language,Accept-Encoding,Sec-Fetch-*
NoOp limiter — used internally for Phase 0 reconnaissance (smoke scans) where rate limiting is undesirable. Satisfies the same acquire()/release() interface but never sleeps.
cli.py CLI entry point, argument parsing, run_scan() pipeline
├── crawler.py Headless Chromium session, URL/JS/endpoint discovery
├── waf_fingerprinter.py WAF vendor + backend framework fingerprinting
├── js_analyzer.py Library detection (regex, CDN headers, package.json)
├── libintel.py CVE database for 40+ libraries (XSS, PP, RCE, DoS)
├── input_surface.py Attack surface: URL params, forms, postMessage
├── dom_sink_scanner.py DOM sink patterns in JavaScript source
├── property_access_hooker.py Runtime prototype property access tracking
├── cspp_detector.py Client-side PP via heap diff (Playwright)
├── sspp_detector.py Server-side PP via black-box response diff
│ └── waf_bypass_engine.py Auto-bypass when requests are blocked
│ ├── waf_fingerprinter.py
│ ├── structural_mutator.py 12 bypass strategies
│ ├── bypass_selector.py WAF-aware ranking
│ └── bypass_validator.py Live validation
├── dom_xss_detector.py DOM XSS via confirmed gadget chains
├── sanitizer_bypass.py DOMPurify / sanitize-html bypass CVE detection
├── gadget_matcher.py Gadget database (60+ chains), version matching
├── gadget_confirmer.py Confirms gadget + CSPP + sink chain in browser
├── poc_synthesizer.py WAF-encoded PoC generation (curl/fetch/HTML/script)
├── cors_scanner.py CORS misconfiguration detection
├── jwt_analyzer.py JWT algorithm analysis, token extraction
├── graphql_recon.py GraphQL schema introspection + operation enum
├── websocket_surface.py WebSocket PP detection
├── oob_handler.py Local mock Interactsh + production OOB integration
├── waf_encoder.py WAF-safe payload encoding (base64, URL, XML variants)
├── dos.py 10 DoS exploitation techniques
├── sustain.py Unified sustain orchestrator (4-phase assault)
├── ai_layer.py Claude-powered report interpretation
├── reporter.py Structured findings → report dict
├── report_formats.py JSON / Markdown / HTML formatters
├── evidence_bundler.py Disclosure ZIP bundler
├── session_store.py Save/resume scan sessions
├── diff_scanner.py Compare two scan reports
└── tests/ 349 unit + integration tests
# Run all tests
pytest tests/ -x -q
# Run with verbose output
pytest tests/ -v --asyncio-mode=auto
# Run integration tests (against lab targets)
pytest integration_tests/ -v
# Validate gadget database
python scripts/validate_gadget_db.pyPPHunter ships with a test lab (lab/app.py) containing vulnerable endpoints for integration testing:
# Start the lab
python -m pphunter.lab.app
# Run integration tests against the lab
pytest integration_tests/ -vThe lab includes: SSPP-vulnerable JSON endpoints, CSPP-vulnerable JavaScript, GraphQL endpoint, CORS-misconfigured endpoint, JWT endpoint, and a DoS-vulnerable WooCommerce-style AJAX endpoint.
| Variable | Purpose |
|---|---|
ANTHROPIC_API_KEY |
Enables AI-powered report interpretation (--analyze) |
HTTP_PROXY / HTTPS_PROXY |
Proxy all HTTP/HTTPS traffic through a proxy |
INTERACTSH_TOKEN |
Auth token for production OOB (--oob-server) |
A full scan produces:
| File | Description |
|---|---|
pphunter_report_TIMESTAMP.json |
Full structured findings in JSON |
pphunter_report_TIMESTAMP.md |
Human-readable Markdown report |
pphunter_report_TIMESTAMP.html |
Styled HTML report with severity indicators |
pphunter_disclosure_TIMESTAMP.zip |
Bundled ZIP containing all of the above + PoC files |
PPHunter is a professional security research tool. Its DoS and sustained assault features must only be used against:
ANYONE YOU WISH TO USE IT ON :)