agentsclimarketplace

Nextjs security

Skill roodlicht/accans-sec-skills/skills/nextjs-security

47 Claude skills for security tradecraft across AppSec, Pentest, Blue Team, and GRC. NL/EU regulatory-anchored. Pattern-level discipline.

Install
npx -y skills add roodlicht/accans-sec-skills --skill nextjs-security

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 4 stars4 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

Next.js security review — middleware auth-bypass patterns (CVE-2025-29927), Server Actions auth/CSRF, Server/Client Component boundary and SSR data leaks, auth.js (NextAuth) config, route handlers as API, Image Optimization SSRF, security headers via middleware.

SKILL.md

13.3 KB, ~3.2k tokens by cl100k_base, as published. Nobody here has run it

Next.js Security

When to use

This skill is the Next.js-specific layer on top of secure-coding and api-security. Next.js has gone through several architectural shifts in recent years (Pages Router, App Router, Server Actions, middleware evolution), and the security implications shift with them. It is also used by teams that do not have a sharp line between front-end and back-end — and that is exactly where bugs live.

Triggers on:

  • A question like "review our Next.js app", "CVE-2025-29927 impact", "make Server Actions safe", "auth.js/NextAuth config review", "middleware auth", "SSR is leaking data into the client bundle", "image optimization SSRF".
  • Presence of next.config.js/.mjs/.ts, middleware.ts in the project root, an app/ directory with page.tsx and layout.tsx, pages/ (older router), "use server" or "use client" directives, NextAuth/auth.js config.
  • A PR that touches middleware, adds Server Actions, converts API routes to Server Actions, or changes auth.js config.
  • Next.js version bumps, especially around security releases.
  • Handoff from security-review or api-security when Next.js is in the stack.

When NOT (handoff)

  • General JS/TS secure-coding → secure-coding.
  • OWASP API Top 10 as a conceptual framework → api-security. Here for the Next.js implementation.
  • SAST tooling (eslint-plugin-security, Semgrep p/javascript) → sast-orchestrator.
  • Dep vulns in package.json / package-lock.jsoncve-triage.
  • Vercel/Netlify deploy config and edge-network policies → iac-security where possible, otherwise platform-specific docs.
  • Secrets in .env.local or Vercel env vars → secrets-scanner.

Approach

Seven phases. Phase 1 (middleware and auth-bypass) is the heart — that is where the CVE-2025-29927-class bug sat and where architectural misconceptions cause problems most often.

1. Middleware and auth-bypass

Next.js middleware runs before every matching request and is often used for authentication gates and redirects. That is precisely why it is an attack surface.

  • CVE-2025-29927 ([verify against https://nextjs.org/blog] and https://github.com/vercel/next.js/security/advisories): An internal header that Next.js used for infinite-loop detection could be set externally, causing middleware to be skipped. Effect: middleware-based auth could be bypassed. Patched in 14.2.25, 15.2.3. Reviewer impact questions:

    • Are you running a version ≥ fix?
    • Was middleware your only auth layer for affected paths? If yes: anyone who could have gained access during the exposure window is an audit target.
    • Are there defense-in-depth auth checks at page or Server-Action level? If "no", this is a pattern-level fix, not just a version bump.
  • More general middleware pattern: middleware is not a safe place for only auth. Defense-in-depth: also check auth in the page/route-handler/Server-Action. Middleware for redirects and header enforcement, not as the sole gate.

  • Open redirects via middleware: return NextResponse.redirect(new URL(request.nextUrl.searchParams.get('next') ?? '/', request.url)) — if next is not validated, this is an open redirect. Allowlist destinations.

  • Matchers: export const config = { matcher: '/admin/:path*' } — a too-narrow matcher does not protect what you thought it protected. Verify all sensitive paths are matched.

2. Server Actions: auth and CSRF

Server Actions ("use server") are RPC endpoints called from a Client Component but executing as server code. They share security concerns with API routes, plus a few of their own.

  • Authentication in the Action itself, not only in the caller. An attacker can call your action hard-coded, bypassing your UI guard.
    'use server';
    export async function deletePost(id: string) {
      const session = await auth();         // do not skip
      if (!session) throw new Error('unauth');
      const post = await db.post.findUnique({ where: { id } });
      if (post.authorId !== session.user.id) throw new Error('forbidden'); // IDOR fix
      await db.post.delete({ where: { id } });
    }
    
  • Input validation: Server Actions receive a FormData or directly-called args. Validate with zod/valibot/yup. Trust nothing that comes from the client.
  • CSRF: Next.js protects Server Actions by default via same-origin checks and an action ID issued only by the server. Cross-origin POST to an action fails. But: that protection leans on the Origin and Host headers. Custom proxy setups can break this; verify Next.js' CSRF guard is still active behind your proxy.
  • Rate-limiting: Next.js has no built-in rate limiter. Use Upstash/Redis/edge-config on the action path, or place auth-sensitive Actions behind a gateway that does rate-limiting.

3. Server/Client Component boundary and SSR data leaks

The App Router introduced Server Components and Client Components. The boundary is meaningful at runtime: what is in a Server Component does not end up in the client bundle, what is in a Client Component does.

  • "use client" boundary: data passed as props into a Client Component lands in the client bundle or in the hydration payload. So: no secrets, no internal IDs, no password_hash, no other user's data that happened to come along in your query, no feature flags that competitors should not see.
  • process.env in Client Components: only NEXT_PUBLIC_* vars are available. Anything else reads as undefined. That is the right default; but an accidentally renamed NEXT_PUBLIC_API_KEY leaks into the production bundle. Grep for NEXT_PUBLIC_ and confirm everything explicitly belongs in public.
  • Hydration mismatch as a leak source: if server and client see different data (e.g. an admin flag), the hydrating client can show data in dev tools that it should not. Server-rendered state contains what you send.
  • Route handler (app/api/.../route.ts) for Pages Router's API routes: treat as any other API endpoint (see api-security). Auth in the handler, not only in the UI.

4. auth.js (NextAuth) and session model

auth.js (rebranded from NextAuth v5) is the de facto auth library for Next.js.

  • Session strategy: database or jwt. JWT strategy stuffs all session data into an encrypted JWT cookie — fast reads, no server-side invalidation. Database strategy has invalidation but requires a DB hit per request. The choice is a trade-off; the JWT default is reasonable for small apps, database for anything where logout really must invalidate.
  • AUTH_SECRET must be cryptographically random (openssl rand -base64 32), in vault or env var, different per environment. See secrets-scanner.
  • Providers: OAuth providers (Google, GitHub, etc.) use PKCE by default in auth.js v5. OK. Watch out for the Custom Credentials provider: you write the authorize function yourself, all credential validation is your responsibility. Verify password hashing (argon2id via the argon2 package or bcrypt), and timing-safe comparison.
  • Callback-URL allowlist: pages.signIn etc. explicit. No dynamic redirect URL from a callbackUrl query param without an allowlist check.
  • Session-cookie flags: auth.js sets HttpOnly, Secure (in prod), SameSite=Lax by default. Do not override unless necessary.

5. Image Optimization, file uploads, other SSRF vectors

  • next/image with external sources: remotePatterns in next.config.js is the allowlist for where Next.js may fetch images. A wildcard hostname is effectively an image-proxy SSRF: someone loads /_next/image?url=<internal-URL> and uses your server to reach internal endpoints. Scope remotePatterns to your exact CDN/bucket domain. Canonical example of this class: [verify against CVE database and Next.js advisories — multiple image-proxy related CVEs have appeared].
  • File uploads via Server Actions: FormData with File — validate server-side on content type, size, magic bytes. Client File.type is spoofable. Store outside public/ to prevent path traversal.
  • Fetch in Server Components to user URLs: classic SSRF (see api-security phase 5). Block private IP ranges, DNS-rebinding protection.
  • next/headers cookies/headers access: only in Server Components and Server Actions, not in Client Components. Well-guarded by default.

6. Security headers via middleware or next.config

Headers are configured in next.config.js headers() or in middleware.

// next.config.mjs
const securityHeaders = [
  { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'X-Frame-Options', value: 'DENY' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
  { key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self' 'nonce-<nonce>'; ..." },
];

export default {
  async headers() {
    return [{ source: '/:path*', headers: securityHeaders }];
  },
};
  • CSP with a nonce is recommended; Next.js documents the nonce pattern via middleware. Avoid 'unsafe-inline' and 'unsafe-eval' where possible — they largely null out CSP's XSS protection.
  • HSTS with preload only if you are on the HSTS preload list or want to be. max-age at least 1 year for preload eligibility.
  • Headers via middleware are more dynamic (per route) but heavier.

7. Misc and verification-loop

  • dangerouslySetInnerHTML — React equivalent of |safe. Only on sanitized content, never directly on user input. Use DOMPurify or sanitize-html for user-generated HTML.
  • eval, new Function, dynamic import(userString) — RCE vectors, never on user input.
  • revalidatePath / revalidateTag from Server Actions — if the path parameter comes from user input, someone can manipulate your cache. Allowlist the paths.
  • noindex on non-production via middleware or robots.txt, to keep staging out of Google by accident.

Verification-loop: Layer 1 (next.config, middleware, layout/page auth checks, Server Actions all walked through?), assumptions ("auth.js works by default" only if you have seen the actual config). Layer 2 (CVE-2025-29927 with fix versions checked against nextjs.org advisories, auth.js v5 API names correct, no invented Next.js version ranges in fix claims).

Output

Next.js security review — <app>
Next.js: <x.y.z> | Router: <App | Pages | mixed>
auth.js / NextAuth: <version, provider list>

Middleware:
  Present:               <yes/no>
  Auth via middleware:   <only layer | part of defense-in-depth>
  Matchers:              <scope>
  CVE-2025-29927 patched:<yes/no>
  Open redirects:        <list>

Server Actions (App Router):
  Number of actions:     N
  Auth check per action: <yes for all | gaps on ...>
  Input validation:      <zod/valibot/... | none>
  Rate-limited:          <yes/no>

Server/Client boundary:
  NEXT_PUBLIC_* exposure: <list, review>
  Secrets in Client props:<grep for password/token/key>
  Hydration leaks:        <visible in dev tools?>

auth.js:
  AUTH_SECRET source:    <vault/env>
  Session strategy:      <jwt | database>
  Providers:             <OAuth + PKCE | credentials + hashing scheme>
  Callback-URL allowlist:<yes/no>

next/image:
  remotePatterns scope:  <specific | wildcard — FINDING>

Security headers:
  HSTS:                  <on + preload>
  CSP:                   <nonce/hash | unsafe-inline — FINDING>
  Frame-Options:         <DENY/SAMEORIGIN>

Version check:
  Latest security release: <date>
  cve-triage handoff:      <N deps with vulns>

Findings (severity-sorted, follow security-review format)
Verification-loop: ...

References

Categories

  • appsec

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,984. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.