Skip to content
Back to skills

Webapp Security Audit

ASecurity

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.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
ai-agentsrustreactrailsgitapisecurity

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 19, 2026

npx -y skills add dustinkeeton/wafflestack --skill webapp-security-audit --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Webapp Security Audit?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Webapp Security Audit
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/dustinkeeton-webapp-security-audit/badge)](https://www.skillsdirectory.com/skills/dustinkeeton-webapp-security-audit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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 <pkg>` / `npm ls <pkg>`)
- **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)
  - `<svg>` 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 `<script src="http://...">` or `<img src="http://...">`.
- Any external `<script>` from a CDN must carry Subresource Integrity (`integrity="sha384-..." crossorigin="anonymous"`) — without it a CDN compromise ships arbitrary code to your users. Prefer bundling over CDN scripts entirely.

### 6. localStorage / sessionStorage / IndexedDB safety

- **Never store secrets** (the storage is readable by any script on the same origin).
- **Validate on read** — storage can be tampered with. Re-narrow the type when reading; reject if the shape is wrong.
- **Use a versioned key prefix** (e.g., `app:v1:records`) so a future schema change doesn't crash users with stale data.
- **Query-cache persistence** (e.g., TanStack Query storage persisters) is fine, but ensure the persister has a key prefix and doesn't persist queries that include sensitive data.

### 7. CI workflow safety

- **No `pull_request_target` with secrets** unless every code path is read-only (this trigger runs in the context of the base branch but with PR code — a known supply-chain footgun).
- **Pin actions by SHA**, not tag (`uses: actions/checkout@<sha>`) for any action that has access to secrets or write permissions.
- **Limit `GITHUB_TOKEN` permissions** to the minimum needed (`permissions:` block at the workflow or job level).
- **Don't echo secrets** in CI logs.

## Audit Checklist

Run through this list on every review:

1. `{{sec.auditCmd}}` — note critical/high findings
2. `{{project.lockfile}}` matches `package.json` (no untracked dependency changes)
3. `git grep -E "(sk-|Bearer |API_KEY|SECRET|TOKEN|AKIA|AIza)"` — no secrets in source
4. After `{{project.buildCmd}}`, `grep -rE "(sk-|API_KEY|SECRET)" <build output dir>/` — no secrets in built output
5. `git grep dangerouslySetInnerHTML` — every hit has a justifying comment + sanitization
6. `git grep -E "target=\"_blank\""` — every hit also has `rel="noopener noreferrer"`
7. `git grep -E "http://"` — only acceptable in `localhost` dev URLs
8. The data-client module validates every external response field before returning
9. localStorage / sessionStorage usage validates types on read

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…