---
name: fableaudit
description: >-
  Deep product security and authorization audit: ownership bounds, share
  grants, IDOR, injection, host policy leaks, secret exposure. Use when you
  need findings first — fixes only after a human picks them.
---

# /fableaudit — you audit; fixes wait for approval

You own scoping, threat modeling, evidence, and the findings report.
Subagents may fan out **read-only** lane work. You never fix while auditing
unless the user explicitly asks to remediate after the report.

This skill is the audit twin of fableplan: same depth, opposite default
(read → judge → report, not plan → edit → ship).

## When to use

- “Audit files / documents for user visibility and share grants”
- “Security audit of X” / find IDOR, injection, or authz holes
- “Who can read this resource?” / “is sharing bounded?”
- Any surface where private data must stay owner-scoped unless a grant says
  otherwise

Do **not** use this for ordinary PR review or for implementing fixes (hand
fixes to fableplan after the user picks findings).

## Phase 1 — Scope (you, alone)

1. **Name the audit target** in plain product language (host + user path),
   not just a folder. Example: “Workspace Files on the product host — list,
   open, share, and download.”
2. **Inventory the asset classes** that hold user data:
   - documents / files / folders / blobs / assets
   - reports / runs / articles
   - shares / invite tokens / grant rows
   - websocket / terminal / session state
3. **Draw the trust boundary** (who is Alice, Bob, anon, admin, other host).
   Assume two logged-in users on the same product unless the user narrows it.
4. **Pick lanes** from the lane set below. Drop lanes that cannot apply; do
   not invent empty lanes.
5. Present a short scope card and get go-ahead unless already approved:

```text
AUDIT TARGET: …
ASSET CLASSES: …
ACTORS: owner | grantee | stranger | anon | admin
LANES: A Authz · B Injection · C Host/policy · …
OUTPUT: numbered findings (Where / What’s wrong / What right looks like)
NO FIXES until you say so.
```

No product edits in Phase 1.

## Phase 2 — Evidence (read-only; parallel OK)

Work the chosen lanes. Prefer **proof over vibe**:

| Proof | How |
|-------|-----|
| Code path | Handler → store query → owner / grant check → response |
| Negative path | Same id, different user → expect 403/404, not 200 |
| SQL / store | Owner (or grant join) on every read/write/list |
| Host policy | Host allow-lists vs actual routes |
| UI only | Flag as **UI-only**; backend must independently enforce |

Rules:

- Absolute paths in private notes. User-facing findings stay plain English.
- Trace **every** verb for each asset: list, get, create, update, delete,
  download, share, resolve-share, export.
- Special focus for files / documents / assets: ownership **and** share-grant
  paths. Share must be an explicit second gate, never “id known ⇒ readable.”
- Launch independent lanes as parallel read-only workers when useful; you
  synthesize. No edits, no deploys from lane workers.
- If a path is unknown / unproven, say so — do not invent a clean bill.

### Lane checklist

**A — Authorization / visibility** — For each asset × verb: is the session
required? Does the store constrain by owner? If shared, is there an explicit
grant check on the same request path? Do list endpoints leak other users’
rows? Can a grantee escalate?

**B — Injection** — SQL string-concat; shell/CLI with unsanitized paths; path
traversal; XSS via unescaped HTML/markdown/SVG; SSRF on user URLs;
prompt/tool text reaching shell or SQL tools without allow-lists.

**C — Host & product policy** — Does a route exist on a host that should not
see it? Cookie domain / Secure / HttpOnly / SameSite vs shared parents.
Cross-product redirects must not carry privileged tokens in the clear.

**D — Session & auth** — Dev access keys in production; session fixation;
missing auth on websocket upgrade; CSRF on cookie-auth state changes; admin
routes requiring a real grant, not just “logged in.”

**E — Data exposure** — Error bodies echoing SQL / internal ids; logs
printing tokens or file bodies; signed URLs guessable without owner; exports
including unauthorized resources.

**F — Share / grant machinery** — Over-broad roles; token entropy / expiry /
revoke; resolvers that load by id then check access — confirm the check
cannot be skipped on any path.

**G — Frontend trust** — Client filtering is not authz. Hidden UI ≠ server
deny. Any client call with a raw id from the URL is an IDOR candidate on the
matching API.

## Phase 3 — Synthesize (you, alone)

1. Deduplicate. One root cause → one finding (many symptoms under it).
2. Severity: **P0** exploitable cross-user or anon data access; **P1**
   privilege / grant bypass or reliable injection; **P2** defense-in-depth /
   info leak; **P3** hygiene / unproven-but-suspicious.
3. Stable numbering for the conversation: first report uses 1…N; later
   messages **keep those numbers**.
4. Every finding uses three headings: **Where** / **What’s wrong** /
   **What right looks like** — plain English, user-standing “Where”.
5. Add a compact severity table **after** the numbered findings (file:line
   allowed only in that table).
6. End with **Remediation gate**: list finding numbers that need a fix plan;
   do not start fixes.

## Phase 4 — Close

- Write an optional durable audit note only if the user asked, or the audit
  is large (≥5 findings). Plans/docs only — no product deploy from the audit
  itself.
- If the user says fix / remediate: hand off to fableplan (or execute) with
  briefs derived from findings — one brief per commit-sized fix; authz fixes
  prefer server-side fail-closed.
- Never mark an audit “clean” because the UI hides a row. Clean means every
  mutating and reading API was checked or explicitly scoped out.

## Judgment boundary

| Lane workers get | You keep |
|------------------|----------|
| File discovery, route lists, “does this query filter owner?” | Threat model, severity, user report |
| Parallel lane digests | Deciding false positives |
| Diff-shaped evidence snippets | Whether to open a fix plan |

| Never during audit | After explicit fix approval |
|--------------------|-----------------------------|
| Product code edits | fableplan / normal ship |
| “Quick harden” drive-bys | Scoped remediation only |
| Deploy / secrets | Still never without user intent |

## Anti-patterns

```text
❌ BAD — Audit = skim handlers; skip list endpoints and share resolvers
❌ BAD — “UI only shows my files” ⇒ call authz done
❌ BAD — Fix P0s in the same turn as the first findings report
❌ BAD — Renumber findings between messages
❌ BAD — File paths in the Where / What’s wrong prose
❌ BAD — Claim clean on an untraced verb (“didn’t check delete”)

✅ GOOD — Every asset × verb has owner or grant proof, or a finding
✅ GOOD — Share path is a separate gate with evidence
✅ GOOD — Unproven called out as unproven
✅ GOOD — Fixes only after the user picks findings
```

## Proof patterns (quick)

**Owner-bound get:** auth → user id → get(resource, owner=user) or get then
deny if owner ≠ user → 404/403 on miss.

**Share-bound get:** auth or share token → resolve share → resource + role →
load → enforce role for verb → never return body if expired/revoked.

**IDOR probe:** As A create R; as B GET/PATCH/DELETE R → expect deny; list
for B must not include R; with A’s share token, only granted verbs work.

---

Published by Academica — https://academica.sh/skills/fableaudit
Version 2026-07-28 · MIT license · install: curl -fsSL https://academica.sh/skills/fableaudit/install.sh | bash
