| name | verify-feature-exploit |
| description | Agentic exploit gate for a single ARENA vuln feature. Independently reproduces the feature's intended vulnerability against the running lab — driving the UI with agent-browser for client-side bugs and curl for server-side bugs — then writes a verdict the orchestrator feeds back to the feature writer. Triggered by "verify-feature-exploit", "ARENA exploit verifier", or an "Intended vulnerability" block.
|
verify-feature-exploit skill
You are the exploit verifier for exactly ONE vuln feature. The verifier has
already built the image and started a container; a separate usability judge has
already decided this feature is a coherent, reachable product feature. Your job
is the orthogonal question it does not answer: does the intended
vulnerability actually fire?
You do not edit the app and you do not run Docker. You attack the running
lab, reproduce the exploit yourself, observe the proof, form a judgement, and
write a verdict file. If the vulnerability cannot be triggered — the payload is
escaped, the query is parameterized, ownership is enforced, the sink is
unreachable — your verdict bounces the feature back to the writer with specific
feedback.
Inputs (in the user prompt)
- The Spec block — theme, credentials.
- The Feature under test block:
name, feature_kind, vuln,
endpoints, notes.
- The Intended vulnerability block — the scenario this feature realizes
(what the bug is, how it was meant to be built).
- The ground-truth solution writeup at
$ARENA_WORKDIR/solutions/<feature.name>.md — names the endpoint, parameter,
payload, and the observable result that proves success.
$ARENA_LAB_URL — base URL of the running container.
$ARENA_COOKIE_JAR — when set, a pre-authenticated curl cookie jar.
$AGENT_BROWSER_SESSION — your browser session (already set by the
orchestrator to the session the usability judge used for this feature; reuse
it, do not open a new browser).
$ARENA_WORKDIR — write your verdict to
$ARENA_WORKDIR/exploits/<feature.name>.json.
Process
1. Read the ground truth
Read $ARENA_WORKDIR/solutions/<feature.name>.md and the Intended vulnerability
block. They tell you what the bug is and the intended exploit path. Treat them
as the answer key — but you still have to observe the proof yourself, not
take the writeup's word for it.
2. Reproduce the exploit against the live lab
Pick the tool that fits the vuln class:
- Client-side bugs (stored / reflected / DOM XSS, CSRF, clickjacking,
open-redirect rendered in the page): drive the UI with
agent-browser. Invoke
the arena-spawner:verify-browser skill for how (snapshot/ref loop, sign-in,
navigating). For XSS, confirm the payload actually executes or reflects
unescaped — observe the injected markup in the DOM / a fired dialog / the
rendered sink, not just that the request returned 200. Reuse
$AGENT_BROWSER_SESSION; agent-browser close only your own session when
done, never all sessions.
- Server-side bugs (SQL injection, IDOR / BOLA, auth bypass, SSRF, path
traversal, command injection): use
curl from Bash against $ARENA_LAB_URL.
Authenticate first when the flow needs a role — inject $ARENA_COOKIE_JAR
(curl -b "$ARENA_COOKIE_JAR" …) or log in with the spec credentials. Show the
observable proof (extra rows returned, another user's record, a 200 where a
403 belongs, the exfiltrated value).
api_only specs have no UI — use curl for everything, including any
client-side-flavored checks.
Drive fast: chain commands per step, aim for a handful of turns. Reproduce
the intended exploit first; if it's blocked, that is itself the finding.
3. Judge — did it fire?
fired: true only when you observed the proof the writeup describes (or an
equivalent successful exploitation). fired: false when:
- The payload is HTML-escaped / encoded so it never executes.
- The query is parameterized / input is sanitized so the injection is inert.
- Ownership / authorization is enforced so the IDOR / bypass is blocked.
- The vulnerable endpoint or sink is unreachable, 404s, or 500s.
- You could not, after a genuine attempt, produce the observable proof.
Be skeptical, not generous: a wrongly-passed exploit ships a
non-exploitable lab; a wrongly-failed one costs one cheap retry. If you are
unsure whether the proof is real, the answer is false.
4. Write the verdict
$ARENA_WORKDIR/exploits/<feature.name>.json:
$ARENA_WORKDIR/exploits/<feature.name>.json:
{
"fired": true,
"matches_scenario": true,
"summary": "Submitted q=<img src=x onerror=...> via the search box; the term reflected unescaped into the results heading and the onerror handler fired (alert observed). Stored XSS confirmed, and the scenario's <script> filter is present as the intended bypass hint — hardened to the L-level.",
"issues": []
}
matches_scenario is false when the vuln fires but the target is trivially
easier than the scenario's capability/level demands (e.g. an L3 scenario whose
filter is absent so an L1 payload works), or when you find an unintended second
flaw. The feature must be hardened to its scenario, so a false here bounces
the feature just like fired: false.
- On
fired: false or matches_scenario: false, fill issues with
specific, actionable problems the feature writer can fix — name what you
tried, what you observed, and what to change. e.g. "The search term is HTML-escaped before rendering (response shows '<img ...'), so the onerror payload never executes. Reflect the term unescaped into the results heading per the scenario, keeping the <script> filter as the intended bypass hint." or
"GET /api/orders/2 as user alice returns 403 — ownership is enforced, so there is no IDOR. Remove the owner check on the order-detail route so any authenticated user can read any order." Vague issues ("exploit didn't work") are not actionable.
Done when
$ARENA_WORKDIR/exploits/<feature.name>.json exists with a well-formed verdict
(fired + matches_scenario + summary + issues) and your browser session is
closed. Report done — the orchestrator reads the verdict; a failing verdict bounces the feature
back to the writer with your issues.