--- name: awesome-leak-audit description: "Audits a public client (extension, app, SPA, CLI, SDK) for what it reveals about the private backend (limits, anti-abuse, backdoors, infra) and client hardening. Use before open-sourcing or a store submission." license: MIT metadata: author: Khasky tags: ["security", "audit", "client", "leak-prevention"] documentation: "https://github.com/khasky/awesome-agent-skills/tree/main/skills/awesome-leak-audit" --- # Public Client Leak Audit Audit a public client codebase that talks to a private backend. Goal: the public surface must be *self-contained* — it may reveal the calls it makes and the data shapes it exchanges (unavoidable for any shipped client), but nothing beyond that. Every extra detail about how the server works is free reconnaissance for an attacker and a lever for abuse. This skill produces three things: a findings list (leaks + client-side security holes, each with `file:line` and severity), a set of applied fixes, and a report with residual recommendations. Reference files (load on demand — read the one you need, don't inline all of them): - [`references/leak-taxonomy.md`](references/leak-taxonomy.md) — the categories of disclosure to hunt, why each matters, and starter search patterns. Read it before the first sweep of the repository. - [`references/rewrite-rules.md`](references/rewrite-rules.md) — the comment/string rewrite rule with before/after examples; how to decide keep-vs-cut. Read it when a finding is about to be rewritten, not while hunting. - [`references/client-hardening.md`](references/client-hardening.md) — runtime-independent client-side security checklist (capabilities, cross-context entry points, tokens, network, build config, supply chain). Read it at the hardening phase, whatever the client type. - [`references/browser-client.md`](references/browser-client.md) — the browser half of that checklist (extension permissions, storage tiers, DOM/CSS sinks, bundler config, npm lifecycle scripts). Load it *with* `client-hardening.md` for an extension, SPA, or web SDK; skip it for a native, desktop, or CLI client. - [`references/report-template.md`](references/report-template.md) — the output report structure. Read it when the findings are settled and the report is being written. ## The core mental model Sort every disclosure into one of two buckets: - Necessary-minimum (keep): the endpoints the client calls, the request/response shapes it actually sends and receives, its own retry/backoff/debounce choices, input validation caps, and the `status → UI behavior` mapping. A public client cannot hide these; pretending otherwise is security theater. - Over-disclosure (fix): anything describing *what the server does with a request*, server-side limits/quotas the client doesn't strictly need, endpoints the shipped client never calls, error branches that mirror internal server logic, anti-abuse mechanics, infra/tech-stack identifiers, private repo/paths, and test scaffolding that encodes backend behavior. The rewrite rule. Client code and tests may state the *contract* ("HTTP 422 → show the unsupported-provider message"). They must not explain *what or why the server does* it ("the server runs a disposable-domain check and rejects with 422"). When a comment explains server behavior, either delete it or reduce it to the client-observable contract. See `references/rewrite-rules.md`. ## Workflow Scale effort to the request: a quick "does this leak anything" is phases 1–2; "scrub before open-sourcing" or "full audit" is all six. For a large codebase, fan out phase 2 across parallel read-only agents (one per taxonomy cluster) and merge their `file:line` findings — but do the scoping in phase 1 yourself first, and pass every agent the public/private boundary from phase 1 or an unavoidable disclosure gets mis-flagged. Keep phase 4 remediation single-writer and serial — parallel editors of the same files collide. Resource preflight (before fan-out): cap concurrency at `min((cores−1)×0.75, free_gb×0.7/per_agent, 6)`, `per_agent` ≈ 0.7 GB for read-only agents; go serial if CPU load > 85% or free RAM < 2×per_agent; recompute before each wave; where the runtime caps sub-agent concurrency itself, defer to it. ### Phase 1 — Scope the public/private boundary Before searching, establish what "private" means for *this* product. Do not skip this — the whole audit is relative to this boundary. - Identify the public artifact(s) under audit and the private counterparts (backend, admin tools, infra, monorepo siblings). Ask the user or infer from a `AGENTS.md`/`README`/`CONTRIBUTING` if the split isn't obvious. - List the product's backend stack, hosting, DB, anti-abuse mechanisms, and any test/staging affordances — so you recognize a leak when you see one. If you don't know them, that's the first question to the user. - Write down what counts as necessary-minimum for this client (its real endpoints and payloads) so you don't waste effort flagging the unavoidable. Done when: the public artifact and its private counterparts are named, the backend stack behind them is known or asked about, and the necessary-minimum surface is written down. ### Phase 2 — Sweep for leaks Walk the taxonomy in `references/leak-taxonomy.md`. Cover the whole repo, not just `src/`: tests/e2e, docs, README/CHANGELOG, CI/workflow files, `.env*` and their `.example` twins, build/config files, package manifests (scripts, `postinstall`), and locale/i18n strings (they ship inside the package). Sweep the taxonomy's starter patterns with whatever search the environment gives you, in one pass over the target directory, with build output, dependency trees, version-control internals, vendored code and lockfiles excluded, and group the hits by category so the reading has an order. Then read every hit in context — a pattern match is a lead, not a verdict. For each real finding record `file:line`, a short quote, and a one-clause reason. An area that came back clean is not recorded and never reaches the report — it costs the reader tokens and gives them nothing to act on. Only an area you could not check gets written down, with the reason. For each confirmed leak, sketch the attacker's next step as a one-line attack path — leaked detail → what it enables → why it matters — and rate severity by how *easy* the abuse is, not only how bad the worst case would be. In vendored/third-party code, add a supply-chain quick pass for obfuscation patterns: long `atob` strings, `String.fromCharCode` chains, `\xNN` escape runs. Extend description–behavior mismatch to dependencies: a package advertising "zero deps / no telemetry" that phones home is the same tell — check `npm view --json` (unpacked size, file count) against the claim, then read the actual source from the tarball (`curl -sL $(npm view dist.tarball) | tar -xzO package/index.js | head`). Also pre-scan the repo for hidden instructions an attacker planted for *your* agent: `grep -rn "