# Framework Security Checks

> Framework-specific security checks for React, Next.js, Express, Fastify, Vue, Nuxt, Svelte, and Hono. Use when auditing a project built with a specific JavaScript framework or when the user asks for framework security review.

- Skill: `leo4135/framework-security-checks` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add leo4135/framework-security-checks`
- Raw SKILL.md: https://api.skillmd.com/api/skills/leo4135/framework-security-checks/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: leo4135 (https://skillmd.com/u/leo4135)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/leo4135/framework-security-checks

---


# Framework-Specific Security Checks

Detect framework from `package.json`, then apply the matching section.

```bash
node -e "const p=require('./package.json'); console.log({...p.dependencies,...p.devDependencies})" 2>/dev/null
```

---

## React

- [ ] No `dangerouslySetInnerHTML` without DOMPurify sanitization
- [ ] User-controlled `href` in links validated (`javascript:` blocked)
- [ ] Keys not derived from user input in security-sensitive lists
- [ ] Third-party components audited for XSS
- [ ] Environment variables: only `REACT_APP_*` / `VITE_*` in client (never secrets)

```bash
rg -n "dangerouslySetInnerHTML|innerHTML" --glob "*.{jsx,tsx}"
```

---

## Next.js (App Router & Pages)

- [ ] Server Actions validate auth + input on every invocation
- [ ] `middleware.ts` covers all sensitive routes (not bypassable via direct API)
- [ ] `next.config.js` headers: CSP, HSTS, X-Frame-Options
- [ ] `images.domains` / `remotePatterns` allowlist (no open proxy)
- [ ] Dynamic routes: `params` validated before DB queries
- [ ] `NEXT_PUBLIC_*` vars contain no secrets
- [ ] Server Components don't leak secrets to client props
- [ ] `revalidatePath`/`revalidateTag` not callable by unauthenticated users

```bash
rg -n "'use server'|use server" --glob "*.{js,ts,jsx,tsx}"
rg -n "NEXT_PUBLIC_" --glob ".env*"
ls middleware.ts 2>/dev/null && cat middleware.ts
```

See [nextjs.md](references/nextjs.md) for detailed checks.

---

## Express

- [ ] `helmet()` configured with strict CSP
- [ ] `express.json({ limit: '...' })` body size limit
- [ ] Rate limiting (`express-rate-limit`) on auth routes
- [ ] `req.params` / `req.query` validated, not passed raw to DB
- [ ] Static file serving doesn't expose `.env`, `node_modules`
- [ ] `app.set('trust proxy', ...)` configured correctly behind reverse proxy
- [ ] No `res.send(userInput)` without encoding

```bash
rg -n "app\.(get|post|put|delete|use)\(" --glob "*.{js,ts}" 
rg -n "helmet|rateLimit|csrf" --glob "*.{js,ts}"
```

See [express.md](references/express.md).

---

## Fastify

- [ ] JSON schema validation on all routes (`schema` option)
- [ ] `@fastify/helmet` registered
- [ ] `@fastify/rate-limit` on sensitive routes
- [ ] `@fastify/cors` with explicit origin allowlist
- [ ] `trustProxy` set correctly

---

## Vue / Nuxt

- [ ] No `v-html` with unsanitized user content
- [ ] Nuxt `runtimeConfig` secrets not in `runtimeConfig.public`
- [ ] Nuxt server routes (`server/api/`) have auth checks
- [ ] `useFetch`/`$fetch` SSRF: URLs not user-controlled
- [ ] Vue router guards + server-side auth (not guards alone)

```bash
rg -n "v-html" --glob "*.{vue,js,ts}"
rg -n "runtimeConfig" --glob "nuxt.config.*"
```

---

## Svelte / SvelteKit

- [ ] `{@html}` only with sanitized content
- [ ] `+server.ts` endpoints validate auth
- [ ] Form actions validate CSRF (SvelteKit built-in) + auth
- [ ] `$env/static/public` vs `$env/static/private` used correctly
- [ ] `hooks.server.ts` enforces session on protected routes

---

## Hono

- [ ] `validator` middleware on all routes
- [ ] `secureHeaders()` middleware applied
- [ ] `cors` with explicit origins
- [ ] Cloudflare Workers: secrets via bindings, not env literals
- [ ] `c.env` bindings typed via generated types

---

## Node.js (General)

- [ ] No sync file/network ops blocking event loop on hot paths
- [ ] `fs` operations use resolved paths with prefix validation
- [ ] `crypto.randomBytes` for tokens (not `Math.random`)
- [ ] TLS cert validation not disabled (`rejectUnauthorized: false`)
- [ ] `npm` scripts don't execute untrusted postinstall hooks blindly

---

## Detection & Routing

| Detected | Priority checks |
|----------|----------------|
| `next` | Server Actions, middleware, env vars |
| `express` | Helmet, auth middleware coverage, input validation |
| `fastify` | Schema validation, plugins |
| `react` (CRA/Vite) | XSS, client secrets |
| `vue` / `nuxt` | v-html, server routes, runtimeConfig |
| `@sveltejs/kit` | +server auth, {@html} |
| `hono` | validator, secureHeaders, bindings |

## Finding Format

```markdown
### [Framework] Finding Title
- **Framework:** Next.js 14 App Router
- **Check:** Server Action auth
- **Location:** `app/actions/checkout.ts`
- **Issue:** `processPayment` callable without session check
- **Fix:** Add `const session = await auth(); if (!session) throw new Error('Unauthorized')`
```

## References

- [nextjs.md](references/nextjs.md) — App Router, middleware, Server Actions
- [express.md](references/express.md) — middleware stack, common vulns

