TrojanStrike

Security Assessment Report

Target

acme-store.example.com

VERDICT: INSIDE_THE_WIRE
Demonstrated data extraction — the attacker is inside the wire.
TIER: AT_YOUR_RISK REQUESTS USED: 5,214 / 6,000 QUEUED: 2026-08-14 09:30:00 UTC COVERAGE GRADE: GOOD STARTED: 2026-08-14 09:31:12 UTC FINDINGS: 7 + 1 informational FINISHED: 2026-08-14 09:56:03 UTC DURATION: 24m 51s

Executive Summary

Defenses were breached and data extraction was demonstrated: one or more confirmed vulnerabilities were actively exploited to the point of provable, read-only data extraction. Treat this as a confirmed compromise — immediate remediation and incident response are required.

SeverityCount
CRITICAL2
HIGH2
MEDIUM1
LOW2
INFO1
TOTAL7 + 1 informational

Since Last Scan

since last scan: 3 new, 5 persisting, 1 fixed

NEW: Forged JWT → cross-user order read; JWT algorithm confusion accepts forged tokens; Cross-user order receipt access
FIXED: Directory listing exposed at /backups/

Coverage

GRADE: GOOD REQUESTS: 5214/6000 CHECKS: 17 ran · 1 nothing to test · 0 skipped
CheckOutcomeDetailSurfaceRequests
crawlRAN54 pages, 17 forms, 14 API endpoints mapped—420
tlsRANTLS 1.3, valid certificate—2
cookiesRAN4 cookie(s) across 55 URL(s) — 0 finding(s)—84
headersRAN2 finding(s)—3
js-cveRAN0 finding(s) — 19 script(s) assessed—320
js-secretRAN0 finding(s) — 19 bundle(s) scanned offline—0
exposed-filesRANbaseline 404/18 chars, 44 probes → 0 finding(s)—180
tech-cveRAN1 finding(s)—41
dir-probeRANbaseline 404/18 chars, 52 paths → 0 finding(s)—220
authz-boundaryRAN0 finding(s) — 18 protected route(s) x read-only bypass matrix—300
reflected-xssRAN1 finding(s)—128
dom-xssRAN0 finding(s) — 6 page(s) browser-probed—560
sqliRAN1 finding(s)—760
jwtRAN1 finding(s)—46
idorRAN1 finding(s)—132
api-fuzzRAN0 finding(s) — 14 endpoint(s) fuzzed—1680
cmdiNOTHING_TO_TEST0 injection points inside scope—0
escalationRAN4 confirmed findings escalatable — extraction demonstrated, 1 chain composed—120

Remediation Priority

SeverityFindingUrgency
HIGH Cross-user order receipt access Fix within 24–48 hours
CRITICAL Forged JWT → cross-user order read Fix immediately — active exploitation likely
HIGH JWT algorithm confusion accepts forged tokens Fix within 24–48 hours
CRITICAL SQL injection in product search Fix immediately — active exploitation likely
MEDIUM Reflected XSS in search results page Fix before next release
LOW Missing Cross-Origin-Resource-Policy header on static assets Address in next sprint
INFO Technology detected: Next.js 15.1.2 Informational
LOW X-Powered-By header discloses framework Address in next sprint

Attack Narrative

TimePhaseEvent
2026-08-14 09:31:12 UTCSYSTEMstrike accepted — target acme-store.example.com (AT_YOUR_RISK tier, budget 6000)
2026-08-14 09:33:40 UTCRECONcrawl complete: 54 pages, 17 forms, 14 API endpoints mapped
2026-08-14 09:34:02 UTCRECONtech-cve: GET https://acme-store.example.com/ → 200 — Next.js 15.1.2 fingerprinted
2026-08-14 09:36:05 UTCAUTHcredential login succeeded — session acquired for authenticated checks
2026-08-14 09:38:15 UTCPROBEsqli: error differential on /search?q= — 1 injectable candidate
2026-08-14 09:41:27 UTCBREACHsqli: UNION context confirmed, 7 columns — banner extracted read-only
2026-08-14 09:43:10 UTCBREACHjwt: RS256→HS256 confusion accepted — forged token replayed against an anonymous-rejecting route
2026-08-14 09:44:51 UTCBREACHidor: /api/orders/1042 returned a foreign owner reference — BOLA confirmed
2026-08-14 09:52:41 UTCESCALATEsqli: read-only extraction demonstrated — banner + 1 masked row from customers (SELECT-only ceiling)
2026-08-14 09:54:02 UTCESCALATEattack graph: demonstrated chain — forged JWT → cross-user order read (3 hops, goal data-exfiltration)
2026-08-14 09:56:03 UTCVERDICTINSIDE_THE_WIRE — 8 finding(s): 2 critical, 2 high, 1 medium, 2 low, 1 info
2026-08-14 09:56:03 UTCVERDICTcoverage GOOD — 17 ran, 1 nothing-to-test, 0 skipped; 5214/6000 requests
2026-08-14 09:56:03 UTCVERDICTsince last scan: 3 new, 5 persisting, 1 fixed

Extracted Objectives

Existence and classification only. Full extracted values ship exclusively in the confidential one-time download-and-purge report.

FINDING: SQL injection in product search
METHOD: sql UNION SELECT — banner + masked row read (SELECT-only ceiling)
DEMONSTRATING REQUEST: https://acme-store.example.com/search
CLASSIFICATION: Read-only extraction proven from the customers table: banner PostgreSQL 15.4; sample row alice@*** | or*** (masked).
VALUES: No confidential payload recorded for this extraction (pre-dates the objective harvester).
FINDING: Forged JWT → cross-user order read
METHOD: jwt-forge → idor cross-user read
CLASSIFICATION: hop 1: forged token accepted on an anonymous-rejecting route → hop 2: forged identity replayed against the order API → hop 3: victim order record returned → impact: cross-tenant data read
VALUES: No confidential payload recorded for this extraction (pre-dates the objective harvester).

Attack Chains

Multi-hop attack paths proven (or hypothesized) from confirmed findings — each hop is backed by its own evidence.

CRITICAL
Demonstrated

Forged JWT → cross-user order read

  1. Hop 1Forge a customer session via RS256→HS256 algorithm confusion
    jwt: the public verification key doubles as the HMAC secret — a forged token (sub=219) was accepted at GET /api/orders/me → 200; the anonymous control was rejected 401
  2. Hop 2Replay the forged identity against the order API
    idor: GET /api/orders/1042 with the forged token → 200 — the record is owned by user 219, returned to a session that never authenticated as them
  3. Hop 3Read the victim's order history
    order 1042 payload carried the customer name, delivery address, and itemized receipt of user 219 — a cross-tenant data read demonstrated end-to-end
Any customer's identity can be forged and their full order history read — account takeover with data exposure, no credentials required.
Pin JWT algorithms server-side (reject HS256 for RS256-issued tokens) and enforce object-level authorization on every record fetch.

Findings

CRITICAL
Fix immediately — active exploitation likely

SQL injection in product search

#:1
Category:sqli
CWE:CWE-89
CVSS:9.1
Confidence:98%
Status:OPEN
Diff:PERSISTING
URL: https://acme-store.example.com/search
Field: q
Snippet
GET /search?q=gift' UNION SELECT NULL,version()-- -
UNION context confirmed (7 columns). Read-only extraction demonstrated under the AT_YOUR_RISK ceiling (SELECT-only, ≤5 rows, masked): database banner PostgreSQL 15.4 on x86_64-pc-linux-gnu; sample row from customers — alice@*** | or***.
curl -H 'Accept: text/html' 'https://acme-store.example.com/search?q=gift%27%20UNION%20SELECT%20NULL%2Cversion%28%29--%20-'
The search endpoint concatenates the q parameter directly into a SQL query, allowing an attacker to read arbitrary tables — including customer credentials and order history.
Use parameterized queries for all database access.
Replace string concatenation with bound parameters at every call site. The query builder should never see raw user input — validate and type-check q before it reaches the data layer.
const rows = await db.query(`SELECT * FROM products WHERE name ILIKE '%${q}%'`);
const rows = await db.query('SELECT * FROM products WHERE name ILIKE $1', [`%${q}%`]);
  • https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
  • https://cwe.mitre.org/data/definitions/89.html
Tags: OWASP ASVS V5, PCI-DSS 6.5.1
HIGH
Fix within 24–48 hours

JWT algorithm confusion accepts forged tokens

#:2
Category:jwt
CWE:CWE-347
CVSS:8.1
Confidence:96%
Status:OPEN
Diff:NEW
URL: https://acme-store.example.com/api/orders/me
Forged HS256 token (public verification key reused as the HMAC secret, sub=219) accepted at GET /api/orders/me → 200 with user 219's profile; the anonymous control was rejected 401.
The API trusts the alg header of incoming JWTs. An RS256→HS256 downgrade lets an attacker sign a token with the server's public key as the HMAC secret, forging any customer identity.
Pin the accepted JWT algorithm server-side and reject any token whose alg differs.
Configure the verifier with an explicit allowlist (RS256 only) and never read alg from the untrusted header. Keep HMAC secrets and RSA public keys cryptographically separate so a public key can never double as an HMAC secret.
  • https://cwe.mitre.org/data/definitions/347.html
  • https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html
Tags: OWASP API Top 10, PCI-DSS 8.3
HIGH
Fix within 24–48 hours

Cross-user order receipt access

#:3
Category:idor
CWE:CWE-639
CVSS:8.2
Confidence:97%
Status:OPEN
Diff:NEW
URL: https://acme-store.example.com/api/orders/1042
GET /api/orders/1042 → 200 — authenticated as user A (id 317), response contains user B's order record (owner id 219): customer name, delivery address, and itemized receipt.
curl -H 'Accept: application/json' 'https://acme-store.example.com/api/orders/1042'
Order receipts are fetched by sequential id with no ownership check. Any authenticated user can read any other customer's order record by incrementing the id.
Enforce object-level authorization on every record fetch (CWE-639).
Scope every object lookup to the authenticated principal: fetch the order WHERE id = $1 AND user_id = $2, and return 404 (not 403) when no row matches, so ids cannot be enumerated. Apply the same pattern to every id-addressable resource.
  • https://owasp.org/www-project-api-security/ — API1:2023 Broken Object Level Authorization
  • https://cwe.mitre.org/data/definitions/639.html
Tags: OWASP API Top 10, PCI-DSS 7.1
MEDIUM
Fix before next release

Reflected XSS in search results page

#:4
Category:reflected-xss
CWE:CWE-79
CVSS:6.1
Confidence:90%
Status:OPEN
Diff:PERSISTING
URL: https://acme-store.example.com/search
Field: q
Markup canary ts9f3k2 reflected unescaped into the results page HTML — string-delimiter breakout confirmed content-type-aware.
curl -H 'Accept: text/html' 'https://acme-store.example.com/search?q=ts9f3k2%22%3E%3Csvg%20id%3Dts9f3k2%3E'
The q parameter is reflected into the results HTML without encoding. A crafted link executes script in the victim's session.
Encode every reflected value for its output context.
HTML-encode q at the template boundary. Never interpolate request parameters into markup without context-aware encoding; add a Content-Security-Policy as defense in depth.
  • https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
Tags: OWASP ASVS V5
LOW
Address in next sprint

Missing Cross-Origin-Resource-Policy header on static assets

#:5
Category:headers
CWE:CWE-942
Status:OPEN
Diff:PERSISTING
URL: https://acme-store.example.com/assets/logo.png
GET /assets/logo.png → 200 without CORP
Static images are served without Cross-Origin-Resource-Policy, leaving them loadable cross-origin (Cross-Site Imaging).
Serve Cross-Origin-Resource-Policy: same-origin on static assets.
Next.js: set security headers centrally in next.config via the headers() function (or in middleware for dynamic cases) so every route — including API routes and RSC payloads — is covered.
// next.config.ts
const securityHeaders = [
  { key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" },
  { key: "Content-Security-Policy", value: "default-src 'self'; object-src 'none'; frame-ancestors 'none'" },
  { key: "X-Content-Type-Options", value: "nosniff" },
  { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
];

export default {
  async headers() {
    return [{ source: "/:path*", headers: securityHeaders }];
  },
};
LOW
Address in next sprint

X-Powered-By header discloses framework

#:6
Category:headers
CWE:CWE-200
Status:OPEN
Diff:PERSISTING
URL: https://acme-store.example.com/
X-Powered-By: Next.js
The X-Powered-By response header reveals the application framework, narrowing an attacker's reconnaissance.
Remove the X-Powered-By header from all responses.
Next.js: set security headers centrally in next.config via the headers() function (or in middleware for dynamic cases) so every route — including API routes and RSC payloads — is covered.
// next.config.ts
const securityHeaders = [
  { key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" },
  { key: "Content-Security-Policy", value: "default-src 'self'; object-src 'none'; frame-ancestors 'none'" },
  { key: "X-Content-Type-Options", value: "nosniff" },
  { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
];

export default {
  async headers() {
    return [{ source: "/:path*", headers: securityHeaders }];
  },
};
INFO
Informational

Technology detected: Next.js 15.1.2

#:7
Category:tech-cve
Status:OPEN
Diff:PERSISTING
URL: https://acme-store.example.com/
self.__next_f RSC payloads, /_next/static/ asset URLs
The runtime fingerprints as Next.js 15.1.2 (App Router markers). No known CVEs in the curated database apply to this version.
Keep the framework updated as patches ship.