category: fleet-family · status: scaffolded (15 tasks, smoke-ready; awaits docker host) · updated: 2026-11-02

webapp-asserts

What — DVWA (ghcr.io/digininja/dvwa + mariadb:10, per upstream compose/env contract) and OWASP Juice Shop (bkimminich/juice-shop, NODE_ENV=ctf) behind state-assertion verifiers. 15 tasks: DVWA — union SQLi, blind SQLi, login auth-bypass (marker via authenticated command exec), stored XSS (DB-row persistence proof), file-upload RCE (uploaded shell echoes the run nonce), command-exec marker, IDOR ghost-user exfiltration, LFI canary; Juice Shop — 7 challenge-mapped tasks (admin access, admin registration, XSS suite, DB schema, info disclosure, forged requests, arbitrary file write) whose per-run random subsets are polled from GET /api/challenges.

Why — The two canonical training web-apps give dense, well-understood attack surface where state (not prose) can prove exploitation — the stepping stone from CTF-style tasks to the procedural randomized environments in stream D. Juice Shop's CTF_KEY env (flags = HMAC-SHA1(CTF_KEY, challenge name), per lib/utils.ts) makes every flag and write-up useless across runs.

Oracles — db_row (SQL state assertion against the DVWA DB — row created/modified = injection side-effect proof, e.g. guestbook payload persistence for stored XSS); js_challenges (server-side scoreboard polling over a per-run sampled subset); agent_secret (challenge–response against per-run planted values: factory_canary table secret, ghost-user surname, LFI file outside the webroot); http_marker (paths that must 404 pre-exploit and return the run nonce post-exploit). Randomized per run: DB credentials, all canaries, ghost user, webroot nonces, CTF_KEY, challenge subset, host ports (DB never published).

Limitations — stored-XSS oracle asserts DB persistence, not rendering (no headless browser yet); auth-bypass proof presumes the authenticated command-exec module (security low); Juice Shop pools are pinned to the current upstream challenge-key set — re-pin on image bumps; db_row checks row existence/match, not full payload semantics. Anti-cheat, smoke commands and TODOs: fleet/webapp-asserts/README.md.