| name | plan-vuln-app |
| description | Plan the feature breakdown for an ARENA vulnerable web app from a Spec. Triggered when the prompt contains "ARENA planner", "plan-vuln-app", or a Spec block followed by an instruction to produce plan.json. Produces plan.json only — no code, no Docker, no builds.
|
plan-vuln-app skill
You are the planner stage of the ARENA generation pipeline. Your only job
is to produce $ARENA_WORKDIR/plan.json — a structured plan that downstream
stages (skeleton, feature writer, sanity) will execute against.
You do not write code, copy templates, run Docker, or touch the
network. You only write plan.json.
Inputs
- A Spec block in the user prompt (id, framework, vulnerabilities,
credentials, app_theme, etc.)
$ARENA_WORKDIR — absolute path where plan.json must be written
What plan.json must contain
{
"spec_id": "<spec.id>",
"app_theme": "<one-sentence elaboration of spec.app_theme>",
"pages": ["home", "search", "profile", ...],
"features": [
{
"name": "product-search",
"feature_kind": "search",
"vuln": "<the capability slug of one of the spec's exploits, e.g. sql-injection>",
"endpoints": [
{"method": "GET", "path": "/api/search", "purpose": "full-text product search; `q` is the injectable input", "vulnerable": true},
{"method": "GET", "path": "/api/search/suggest", "purpose": "typeahead suggestions"}
],
"auth_role": "user",
"notes": "Full-text search over the products table; the `q` query param is the user-controlled search input, reached from the search box in the top nav. Reads the same `products` table the catalog feature seeds and links each hit to product-detail. Shares the `users` table the account feature owns, so the exploit can pivot across to it. The injection technique and difficulty are owned by the capability the spec picked (the orchestrator pins the scenario)."
}
],
"seed": {
"tables": [
{
"name": "users",
"columns": ["id", "username", "password_hash", "role"],
"rows": [
{"username": "admin", "password_hash": "<bcrypt of Admin123!>", "role": "admin"}
]
}
]
}
}
Hard rules
- Every spec vulnerability must appear as the
vuln field of at least
one feature. A spec with vulnerabilities: [idor, privesc] must produce
features covering both.
- A feature owns one OR MORE endpoints. Real product features need several
routes — a "checkout" has a cart view, an address step, and a submit; a "blog"
has list, detail, create, edit, delete. List every route the feature exposes in
its
endpoints array (method, path, a short purpose). Do NOT atomize a
real feature into one-endpoint mini-features. For a resource with many similar
routes, a single feature can expose them all (path/param-based routing).
- Endpoints (method + path) are unique across the whole plan. The same path
under different methods is fine (
GET /api/posts vs POST /api/posts); the same
method+path twice is not.
- A vuln feature flags at least one endpoint
vulnerable: true — the route(s)
that actually carry the flaw. Supporting features leave every endpoint
non-vulnerable (the default).
- Features must make business sense for
spec.app_theme. An e-commerce
app gets product search, reviews, checkout — not a generic "vuln endpoint".
- Don't host two vulns in one feature unless the spec lists fewer features
than vulnerabilities (which should be rare).
- The seed must include the credentials from
spec.credentials verbatim.
The downstream stage uses these to log in.
vuln is the capability slug, copied verbatim from one of the spec's
exploits. You do NOT choose a scenario or a level — the spec already fixed the
exact capability and level, and the orchestrator resolves and pins the
capability scenario after planning. Leave scenario out of plan.json; design
the feature (placement, inputs, supporting pages, data flow) to complement the
vuln the capability describes.
- Set
auth_role on each vuln feature to the role the exploit runs as:
anon (no login), user, admin, or service. Most exploits run as
user. The verifier pre-logs-in as this role before replaying the exploit.
- Write rich, detailed
notes (a short paragraph, not a phrase). This is
the only place you hand the downstream stages your product design intent, so
spend words here. Each feature's notes should cover:
- What the feature does in product terms, and which pages/UI it surfaces in.
- For vuln features: which input/param/field carries the untrusted data and
how a user reaches it (the form, the page, the click path). The vuln's
technique, difficulty, and any defense are owned by the capability scenario
the orchestrator pins from the spec's exploit pick (which the feature writer
receives verbatim and treats as authoritative) — shape the feature's product
placement to complement the behavior it specifies, rather than re-inventing
the mechanics in notes. Notes that contradict the scenario produce an incoherent
lab.
- Which seed tables/rows it reads or writes, and the shape of that data.
- How it interacts with other features — name them. Shared entities
(the
orders row checkout creates is what the order-history IDOR targets),
navigation links, a role or auth dependency, or a data flow where one
feature produces what another consumes. Cross-feature references are what
make the lab cohere instead of feeling like isolated endpoints, so call
them out explicitly even for supporting features.
Longer notes here cost nothing and save the skeleton/feature stages from
re-inventing your intent.
Process — build the plan in passes
A full plan.json for a large spec is too big to write correctly in one shot.
Work in passes, building the file up incrementally with Edit (not one giant
Write), and track the passes with TodoWrite. Each pass has a narrow job:
Pass 1 — Blueprint
Read the spec block (framework, app_theme, vulnerabilities, credentials,
endpoint_count). Then Write an initial $ARENA_WORKDIR/plan.json with:
spec_id, app_theme (one-sentence elaboration), and features: [] (filled
later).
pages: the page inventory for the theme (at least the band's minimum).
seed: a users table (always, with every spec.credentials row verbatim)
plus whatever content tables the features need (products, comments, tickets,
…). At least 5 rows per content table so an exploit can find something.
Pass 2 — Features (no endpoints yet)
Edit plan.json to add the features list in a single Edit (write the
whole list at once — one Edit per pass, NOT one per feature; many tiny edits
blow the planner's time budget). For each feature set name, feature_kind,
vuln, scenario, auth_role, and rich notes (see the rules above).
- One feature per spec vuln (one-to-one), the
rest supporting (
vuln: "none") to reach the feature band. Supporting
features are built and browser-checked now — genuine, reachable pages, not
filler.
- Pick each vuln feature's
scenario at the level matching the vuln's
difficulty, then Read that yaml under capabilities/ and shape the feature
to complement it.
- Order
features by implementation order. The downstream loop builds them
in the exact order you list, so put a feature before the features that depend
on it (a catalog before the detail/search that link into it). State each
feature's dependencies in its notes.
Pass 3 — Endpoints
Edit plan.json to fill the endpoints arrays for all features — do it in
one Edit (or two), not one Edit per feature. A real feature spans several
routes — list + detail, form + submit, a REST resource's CRUD — so give it its
real route set rather than splitting it into one-endpoint features. For each
endpoint set method, path, and a short purpose; flag the vulnerable
route(s) with vulnerable: true (vuln features only). Keep method+path unique
across the whole plan and stay within the endpoint band.
Pass 4 — Self-check, then report done
Re-read plan.json and confirm the hard rules hold: every spec vuln
covered, feature/endpoint/page bands met, endpoints unique, each vuln feature has
a vulnerable endpoint and a matching-level scenario. Fix anything off, then
report done.
What you do NOT do
- Do not copy stack templates. That is the skeleton stage.
- Do not write any Python / JS / Dockerfile.
- Do not start any container or service.
- Do not call out to the network.
- Do not write
solution.md or manifest.json.
On validation feedback
If the orchestrator comes back with "the file failed validation: ",
fix only the listed fields in plan.json and report done again. Do not
rewrite the whole plan — preserve everything that wasn't flagged.
Done when
$ARENA_WORKDIR/plan.json is written and validates against the Spec.