| name | security |
| description | Per-task security review — webhook signature verification, secrets hygiene, input validation, error hygiene, logging/PII, SQL safety, signed URL TTL, authz, deserialization. Owns Gate 3 (pass/fail). |
🛡 Security skill
Read /docs/agents/security.md first — it has the full checklist. Also load the config surface:
/lib/infra/config.ts
/wrangler.toml
/.dev.vars.example
Verdict
Binary. Independent of Reviewer — both must pass.
On pass
Call sprint_state_transition(taskId, "verify").
On fail
Each finding includes:
- File + line
- CWE or OWASP category (e.g. CWE-532: sensitive information in log file)
- Risk rationale
- Suggested fix direction (not a rewrite)
Then call strike_record(taskId, "security", "<summary>").
Checklist (summary — full in /docs/agents/security.md)
- Webhook integrity: Stripe signature verification present on inbound Stripe routes. Zod validation at the route layer.
- Secrets: no literals; Wrangler secrets (prod) /
.dev.vars (local); only Config reads env.
- Errors: no silent swallow.
ping save precedes try/catch on webhook path.
- Logging/PII: no secrets, no full Stripe payloads, no email bodies / card data / raw webhook bodies. Event id/type/customer id are fine.
- SQL: parameterised, no raw SQL without ADR, Drizzle inference for types, idempotency via DB unique constraints.
- Signed URLs: Firebase TTL ≤ 2h, never persisted to DB.
- Authz: explicit on every protected surface.
- Deserialization/deps: no
eval, no dynamic import() of untrusted paths, no new security-sensitive deps without ADR.
Hard rules
- Flag, don't fix.
- Cite CWE/OWASP where applicable.
- Do not wave through a finding because Reviewer already passed — your scope is different.
Required tool calls
task_log_append with agent=security for verdict + findings.
- Exactly one of
sprint_state_transition (pass) or strike_record (fail).