--- name: webapp-security-audit description: Security auditing for {{project.name}}, a browser-delivered web app. Covers dependency hygiene, XSS prevention, secret leakage in client bundles, validation of third-party data, CORS / mixed content, browser-storage safety, and CI workflow safety. Use when reviewing code for security vulnerabilities or setting up security guardrails. user-invocable: false --- # Security Audit Standards {{sec.threatModelIntro}} Focus areas, in priority order: ## Priority Areas ### 1. Dependency hygiene - **Run audit on every dep change:** `{{sec.auditCmd}}` (production deps; run the dev-inclusive variant as a separate report). - **Vet new deps:** for any package added in the diff, check on npmjs.com: - Weekly downloads (≥ 10k unless niche) - Last publish date (within 12 months) - Maintainer count (single-maintainer = higher risk) - GitHub repo activity (open issues, recent commits) - Transitive bloat (`pnpm why ` / `npm ls `) - **Flag typo-squats** — packages with names that are off-by-one from popular packages. - **Lockfile is the source of truth.** Reject PRs that modify `package.json` without updating `{{project.lockfile}}`. ### 2. XSS prevention - **Forbidden in JSX/templates unless explicitly justified:** - `dangerouslySetInnerHTML` (or the framework's raw-HTML equivalent) — must have a comment justifying it AND show input is sanitized (DOMPurify or equivalent) - `` constructed from variable strings - `innerHTML` / `outerHTML` assignments via refs - **URL injection:** `href={...}` and `src={...}` must validate that the value is `https:` or a relative path. Never accept arbitrary strings from user input or third-party data. - **`target="_blank"`** must include `rel="noopener noreferrer"`. - **Markdown rendering:** if any markdown is rendered, use a sanitizing renderer (e.g., `react-markdown` with `rehype-sanitize`) — never raw HTML. ### 3. Secrets in the client bundle - **The bundle is public.** Anything exposed via the bundler's public env mechanism (e.g. `import.meta.env.VITE_*`) ships to the browser. Treat all such env vars as public. - **Grep the source and the build output** for likely secret patterns: `sk-`, `Bearer `, `API_KEY`, `SECRET`, `TOKEN`, `Authorization`, `AKIA[A-Z0-9]{16}`, `AIza[A-Za-z0-9_-]{35}`. - **No private keys, tokens, or credentials should appear in the build output** after `{{project.buildCmd}}`. Inspect the production build output, not just source. - **If you need a real secret** (e.g., a paid API key), it MUST live behind a server proxy — never in the browser. ### 4. Validation of third-party data {{sec.dataSource}} is untrusted external input. Treat its responses as adversarial: - Every field used downstream must be **type-narrowed** at the boundary (schema library or hand-written guards). - **Never** pass response strings into `dangerouslySetInnerHTML`, `eval`, `new Function()`, or as a URL. - **Reject malformed records** rather than crashing — log and skip. - **No string concatenation into selectors or DOM APIs** (e.g., `document.querySelector("#" + record.name)` — vulnerable if `name` contains a `]`/`'`/etc.). ### 5. CORS / mixed content - All external endpoints MUST be `https://`. Search for `http://` in source — it shouldn't appear except in localhost dev URLs. - An endpoint that reflects `Access-Control-Allow-Origin` is usable by any origin — do not assume responses are unique to your app. - Do not use ``. - Any external `