T09 · Insecure Skill Coding Practices
- Location
src/runner.ts:284- Finding
Plan-Level Hooks Bypass the Risk Authorization Gate
- Content
View full analysis
0; if (plan.setup && plan.setup.length > 0 && hadRunnable) { log.info(c.cyan("▶ plan setup") + c.dim(` — ${plan.setup.length} step(s)`)); const setupError = await runPlanHook(plan.setup, ctx, "plan setup"); if (setupError) { const reason = redactString(`plan setup failed: ${setupError}`); log.err(reason); for (const p of runnable) { results.push(blocked(p.tc, p.driver, reason)); log.warn(`${p.tc.id}: ${reason}`); } runnable = []; } } ``` ```ts if (plan.teardown && plan.teardown.length > 0 && hadRunnable) { log.info(c.cyan("▶ plan teardown") + c.dim(` — ${plan.teardown.length} step(s)`)); const teardownError = await runPlanHook(plan.teardown, ctx, "plan teardown"); if (teardownError) log.warn(redactString(`plan teardown (best-effort) did not fully complete: ${teardownError}`)); } ``` The corresponding schema explicitly exposes the same unrestricted step language to hooks: ```ts setup: z .array(Step) .optional() .describe( "steps run ONCE before any case (in a throwaway context) to seed shared state; if any fails, every runnable case is marked blocked. TRUSTED, author-controlled fixtures: plan hooks run UNGATED — they are NOT subject to the per-case risk/--allow-risk gate, so keep destructive operations out of the ...[truncated 2194 chars]- Remediation
View remediation
