Nextjs security
Skill hlsitechio/claude-skills-security/appsec-stack-pack/nextjs-security
Defensive security audit skills for Claude — tech-stack-keyed and audit-domain-keyed packs for SaaS apps.
npx -y skills add hlsitechio/claude-skills-security --skill nextjs-securityAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Security audit specific to Next.js applications including App Router and Pages Router, Server Actions, middleware, Route Handlers, Server Components, environment variable exposure (NEXT_PUBLIC_), getServerSideProps/getStaticProps secret leakage, Image Optimization SSRF, and Next.js-specific authentication patterns. Use this skill whenever the user mentions Next.js, App Router, Pages Router, Server Actions, RSC, server components, middleware.ts, route handlers, NEXT_PUBLIC_, Vercel deployment patterns, next.config.js, or asks "audit my Next.js app", "is my middleware safe", "Server Actions security", "Next.js auth review". Trigger when the codebase contains a `next.config.js`/`next.config.mjs`/`next.config.ts` file, `app/` directory with `page.tsx` files, or `pages/` directory with Next.js conventions.
SKILL.md
10.4 KB, as published. Nobody here has run it
Next.js Security Audit
Audit a Next.js application for framework-specific vulnerabilities. Covers App Router (13+) and Pages Router. Defensive focus.
When this skill applies
- Reviewing Next.js apps for security issues
- Auditing Server Actions, Route Handlers, middleware
- Reviewing environment variable usage (the
NEXT_PUBLIC_trap) - Checking authentication patterns specific to Next.js
- Identifying SSRF in
next/imageconfigurations - Auditing the differences between Server and Client Components
Use other skills for: generic React patterns (react-security), backend services Next calls (nodejs-express-security etc.), auth providers (clerk-security, nextauth-security), Vercel platform settings (vercel-platform-security).
Workflow
Follow ../_shared/audit-workflow.md. Next.js-specific notes below.
Phase 1: Stack detection
- Next.js version (13, 14, 15 — App Router behaviors differ)
- Router model: App Router (
app/), Pages Router (pages/), or hybrid - Deployment target: Vercel, self-hosted Node, edge runtime, static export
- Auth: NextAuth/Auth.js, Clerk, custom JWT, Supabase Auth, other
Phase 2: Inventory
# Layout
find . -name 'next.config.*' -not -path '*/node_modules/*'
find app -type f \( -name 'page.tsx' -o -name 'route.ts' -o -name 'layout.tsx' \) 2>/dev/null | head -20
find pages -type f \( -name '*.tsx' -o -name '*.ts' \) 2>/dev/null | head -20
# Server Actions (App Router)
grep -rn "'use server'" app/ src/ 2>/dev/null | head -50
# Middleware
find . -name 'middleware.ts' -o -name 'middleware.tsx' -o -name 'middleware.js' 2>/dev/null | head
# Environment variable references
grep -rn "process.env" app/ src/ pages/ 2>/dev/null | head -50
# next/image config (image optimization)
grep -n 'images:\|remotePatterns\|domains:' next.config.* 2>/dev/null
Phase 3: Detection — the checks
Environment variables — the NEXT_PUBLIC_ trap
- NXT-ENV-1 Variables prefixed with
NEXT_PUBLIC_are inlined into the client bundle at build time. Anything not strictly public must NOT have this prefix. - NXT-ENV-2 Common mistakes:
NEXT_PUBLIC_STRIPE_SECRET_KEY,NEXT_PUBLIC_DATABASE_URL,NEXT_PUBLIC_API_KEY— all of these have shipped to production at multiple companies. Audit everyNEXT_PUBLIC_for "is this really public?" - NXT-ENV-3 Verify by building and inspecting:
npm run build && \ grep -rhE 'NEXT_PUBLIC_[A-Z_]+' .next/static/chunks/*.js | sort -u # If any NEXT_PUBLIC_*_SECRET or NEXT_PUBLIC_*_KEY values show up, that's a leak - NXT-ENV-4 Server-only secrets read from
process.env.SOMETHING_SECRETonly in server components, server actions, route handlers, orgetServerSideProps/getStaticProps. Never reference them in a Client Component or shared utility imported by both.
Server vs Client Components (App Router)
- NXT-RSC-1 Files with
"use client"are Client Components and ship to the browser; nothing in their import graph can contain secrets. - NXT-RSC-2 Files without
"use client"inapp/are Server Components — they can read secrets but must NOT pass them as props to Client Components (props serialize to the client). - NXT-RSC-3 Use the
server-onlypackage to fail-fast on accidental client imports of server modules:
If any Client Component transitively imports this, the build fails.// lib/db.ts import 'server-only'; export const db = createDbClient(process.env.DATABASE_URL!); - NXT-RSC-4 Use
client-onlysimilarly for browser-only modules.
Server Actions
Server Actions ("use server") are POST endpoints generated by Next, callable from forms or directly from Client Components. They're a common new XSS-equivalent attack surface.
- NXT-SA-1 Every Server Action checks authentication. There's no implicit auth — Next doesn't add one.
'use server'; import { auth } from '@/lib/auth'; export async function deletePost(postId: string) { const session = await auth(); if (!session?.user) throw new Error('Unauthorized'); // ... and check the user owns the post } - NXT-SA-2 Server Actions check authorization on the specific resource — not just "is user authenticated" but "does user own/have-access-to this object".
- NXT-SA-3 Input validated with Zod or similar; never trust the shape of the FormData / serialized args.
- NXT-SA-4 Server Actions don't accept
userId/tenantIdas args — derive from session. - NXT-SA-5 Mutation Server Actions handle CSRF correctly. Next has built-in protection for Server Actions called via form submission with the same-origin policy, but custom invocations need verification.
- NXT-SA-6 Server Actions that perform sensitive operations have rate limiting (no built-in; use a Redis/Upstash counter).
Route Handlers (App Router) and API Routes (Pages Router)
- NXT-RH-1 Every Route Handler in
app/.../route.tsand every API route inpages/api/checks auth. - NXT-RH-2 No accidental data exposure — handlers return only what the caller is authorized to see.
- NXT-RH-3 CORS configured per handler when needed; not globally permissive.
- NXT-RH-4 Webhook receivers (Stripe, Resend, etc.) verify signatures — see
saas-security-pack/saas-api-security/references/webhook-security.md. - NXT-RH-5 Catch-all routes (
[...slug]/route.ts) validate the captured path; common path traversal vector.
Middleware
middleware.ts runs before every matched request — a powerful place to enforce, also a powerful place to introduce bugs.
- NXT-MW-1 Middleware that performs auth checks: ensure it's actually applied to the routes you think (the
config.matcherfield). - NXT-MW-2 Middleware running on the Edge runtime can't use Node.js APIs; if you need
cryptofor HMAC, use the Web Crypto API. - NXT-MW-3 Middleware doesn't leak: don't put sensitive headers, cookies, or info-disclosure into rewrites/responses from middleware.
- NXT-MW-4 Middleware should not be the only auth check — it's easy to misconfigure matcher and route around. Server Actions / Route Handlers still check.
- NXT-MW-5
request.headers.get('x-forwarded-for')and similar are spoofable client-side except behind a properly-configured reverse proxy. Don't use for security decisions without verifying the proxy chain.
Image Optimization SSRF
next/image can fetch from any URL listed in images.remotePatterns / images.domains in next.config.js and proxy through your server. Bad configs become SSRF.
- NXT-IMG-1
images.remotePatternslists specific hostnames; no wildcards like**. - NXT-IMG-2 No legacy
images.domains: ['*']config. - NXT-IMG-3 Self-hosted Next.js: image optimizer can fetch internal IPs unless restricted. The Vercel-hosted version blocks RFC1918; self-hosted defaults more permissive.
- NXT-IMG-4 If users can supply image URLs (avatars, embeds), the URLs go through
next/imagewhich proxies through your server — making your server the source IP for the fetch. Validate URLs before passing to next/image.
// BAD
module.exports = {
images: {
remotePatterns: [{ protocol: 'https', hostname: '**' }], // any host
},
};
// GOOD
module.exports = {
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'images.yourcdn.com' },
{ protocol: 'https', hostname: '*.s3.amazonaws.com', pathname: '/yourbucket/**' },
],
},
};
Session and auth handling
- NXT-AUTH-1 Session cookies follow the patterns in
saas-security-pack/saas-frontend-hardening/references/cookie-config.md. - NXT-AUTH-2 If using NextAuth: see
nextauth-securityskill. - NXT-AUTH-3 If using Clerk: see
clerk-securityskill. - NXT-AUTH-4 Custom JWT: validate signature on every request; rotate JWT secret periodically; see
saas-security-pack/saas-code-security-review/references/jwt-validation.md. - NXT-AUTH-5 Login redirect URLs validated against allowlist (open redirect via
callbackUrl=...).
Static export vs runtime
- NXT-EXP-1 Static-exported pages don't run server logic at request time; auth checks intended to run server-side don't. Confirm the deployment mode matches the security model.
next.config.js security flags
- NXT-CFG-1
headers()configured to add CSP, HSTS, X-Content-Type-Options, etc. (seesaas-security-pack/saas-frontend-hardening). - NXT-CFG-2
poweredByHeader: false(removesX-Powered-By: Next.js— info disclosure). - NXT-CFG-3
reactStrictMode: true— not strictly security, but surfaces hydration mismatches that can have security implications. - NXT-CFG-4 Custom redirect / rewrite rules don't accept user-controllable targets without validation (open redirect).
Dependency hygiene
- NXT-DEP-1 Next.js version is a recently-patched release. Several Next.js versions have had Critical CVEs:
- CVE-2024-46982 (cache poisoning on Pages Router)
- CVE-2024-34351 (SSRF via Server Actions)
- CVE-2025-29927 (middleware bypass — fixed in 14.2.25 / 15.2.3)
- older CVEs in 13.x Pin to the latest patch of your supported major; review release notes for security fixes.
Phase 4: Triage
Critical class examples:
NEXT_PUBLIC_*_SECRETenv vars (definitive client leak)- Server Action without auth check performing sensitive ops
- Middleware-only auth bypassable via specific URL pattern (see CVE-2025-29927 class)
- next/image with wildcard remote patterns
- Server Component passing secret-bearing prop to Client Component
Phase 5: Report
Use ../_shared/findings-schema.md. Prefix IDs with NXT-.
References
references/app-router-patterns.md— Server Actions, RSC, middleware patterns and pitfalls