Imported from ClementG91/Claude-NextJs-PentestKit (
.claude/skills/security-audit/SKILL.md). Install upstream withnpx skills add ClementG91/Claude-NextJs-PentestKit --skill security-audit. Copyright stays with the author.
Security Audit Skill
Full autonomous security audit (SAST + DAST) for Next.js / SaaS multi-tenant applications. The user says "/security-audit /path/to/app" and Claude Code runs everything automatically and presents results. Fix is NEVER automatic -- only applied when the user explicitly asks.
How it works
This skill is a Claude Code overlay. The Python scanner is the engine, Claude Code is the brain.
- Python CLI = deterministic scanner (SAST, DAST, scoring, reports)
- Claude Code = intelligent analysis (executive summary, deep code review, fix orchestration)
No external API keys needed. Claude Code is the LLM.
Part 1: AUDIT (autonomous -- triggered by "/security-audit" or "audit my app" / "scan" / "pentest")
Target application: $ARGUMENTS
Step 1: Reconnaissance
- Verify the target application directory exists:
ls $ARGUMENTS/package.json - Verify the user has authorization to test
- Detect the framework by reading
package.json:- Next.js version (check for v16+ -> proxy.ts vs middleware.ts)
- Package manager (npm/pnpm/yarn/bun -- check lockfile)
- Auth library (auto-detected from 15+ known libraries -- see Auth Detection below)
- Check if the app is already running or needs auto-start
Step 2: Automated Scan
ALWAYS use the full scan command by default. The --start flag auto-starts the dev server. Only fall back to SAST-only if the target has no package.json or no start script.
Default command (ALWAYS try this first):
IMPORTANT: The full scan can take 3-8 minutes depending on the app size. Use a 10-minute timeout on the Bash call.
nextjs-pentestkit scan $ARGUMENTS --start --fix-deps -f all
(Run this with timeout: 600000 on the Bash tool call)
This starts the app, runs ALL 9 phases (SAST + DAST), and generates JSON + HTML reports automatically.
Fallback — SAST only (ONLY if the target is not a runnable Node.js app):
nextjs-pentestkit sast $ARGUMENTS
Note: sast does NOT generate JSON/HTML/PDF reports. Always prefer scan --start -f all.
If nextjs-pentestkit is not in PATH:
python -m agent.cli scan $ARGUMENTS --start --fix-deps -f all
(Same 10-minute timeout applies)
The scanner runs 9 phases automatically:
- Phase 0: Docker sandbox setup (optional)
- Phase 1: SAST -- 20+ patterns, CVE scanner, extended checks, dependency audit
- Phase 1.5: Auth Discovery -- dynamic detection of 15+ auth libraries + ORM + middleware
- Phase 2: API Cartography -- endpoint discovery via probing
- Phase 3: Auth Testing -- JWT manipulation (bearer auth only)
- Phase 4: IDOR Testing -- cross-tenant access verification
- Phase 5: Escalation -- privilege escalation testing
- Phase 6: Business Logic -- rate limiting, race conditions, mass assignment
- Phase 7: DAST Verification -- 55 dynamic tests (headers, CSRF, CVE-2025-29927, SSRF, etc.)
- Phase 8: Scoring + Report generation
Step 3: Read Scan Results
This step is critical. After the scan completes, find and read the JSON report:
ls -t $ARGUMENTS/reports/report_*.json | head -1
Then read the entire JSON file. The report contains:
metadata: scan_id, target, duration, endpoints countsecurity_score: 0-100 (formula: 100 - critical20 - high10 - medium*5)summary: base text summary from scoring enginefindings[]: each finding with severity, category, evidence, remediation, CVSS, curl PoCphase_log[]: status of each phase (passed/skipped/error with reason)statistics: counts by severity and categoryauth_profile: full auth discovery results includingclaude_hints
Step 4: Deep Code Analysis (guided by claude_hints)
IMPORTANT: Use the auth_profile.claude_hints from the JSON report to focus your analysis.
The scanner produces structured hints to guide this step:
claude_hints.files_to_read-- exact files to read for this auth libraryclaude_hints.critical_checks-- specific security checks based on detected featuresclaude_hints.library_specific.known_vulns-- library-specific vulnerability patternsclaude_hints.attack_playbook-- ordered test plan for the specific auth setupclaude_hints.security_posture-- detected strengths and weaknesses
Files to always read (in addition to hint-specified files):
- All
src/app/api/**/route.tsfiles (every API endpoint) src/proxy.ts(Next.js 16+) orsrc/middleware.ts(older versions)next.config.ts/next.config.js/next.config.mjs- Auth configuration (path from
auth_profile.auth_config_file) - Validation schemas (
src/lib/validations.tsor similar) - Rate limiting implementation
.env.example(to understand expected env vars)package.json(framework versions, dependencies)
Auth-library-specific checks (use detected library from auth_profile):
For Better Auth:
- Check
disableSignUpin production - Verify
trustedOriginsis set (CSRF protection) - Check if admin plugin endpoints are properly guarded
- Verify rate limiting plugin is active
- Check session expiration config
For NextAuth / Auth.js v5:
- Verify NEXTAUTH_SECRET / AUTH_SECRET is strong (>= 32 chars)
- Check CredentialsProvider
authorize()uses hash comparison - Verify
debug: falsein production - Check session strategy (jwt vs database)
- Verify JWT callbacks forward role/tenant claims
For Clerk:
- Check
clerkMiddleware()publicRoutes completeness - Verify
auth()is called in ALL API routes (not just pages) - Check org-level permissions for multi-tenant
- Verify webhook signature validation
For Supabase:
- Verify
getUser()is used (not justgetSession()which trusts JWT without verification) - Check RLS policies on all tables
- Verify
SUPABASE_SERVICE_ROLE_KEYnever used client-side - Check for direct table access without RLS
For Lucia:
- Verify
validateSession()called on every protected request - Check session cookie has httpOnly, secure, sameSite
- Verify CSRF protection is implemented (removed in v3)
- Check password hashing uses Argon2id
For Custom JWT:
- Check algorithm (must be RS256/ES256 or strong HS256)
- Verify expiration is set and reasonable
- Test alg=none vulnerability
- Check secret strength and storage
For Custom password (bcrypt/argon2):
- Check bcrypt cost factor >= 10
- Verify timing-safe comparison
- Check session management after password verification
What to check manually (all libraries):
- Business logic flaws (payment bypass, license key leakage, race conditions)
- Auth flow completeness (is session actually validated or just cookie-present?)
- Schema-to-code mismatches (validation regex doesn't match generator output)
- Data exposure in API responses (returning too much PII)
- Proper error handling (stack traces leaked?)
- Framework-specific best practices
Next.js 16 specific checks:
- Deprecated
middleware.ts-> must beproxy.tswithexport function proxy() - proxy.ts uses Node.js runtime only (edge runtime removed)
skipMiddlewareUrlNormalize->skipProxyUrlNormalize- Turbopack is default -- check for custom webpack configs
cookies(),headers(),params,searchParamsare async-only
Step 5: Executive Report
Present to the user:
-
Security Grade and Score
- Score X/100 (Grade A-F)
- A (90-100), B (80-89), C (60-79), D (40-59), F (0-39)
-
Auth Profile Summary
- Library detected: name + version
- Session mechanism: cookie / bearer / hybrid
- ORM: prisma / drizzle / etc.
- Security features: 2FA, email verification, rate limiting, password policy
- OAuth providers detected
- Middleware protection coverage
- Use
claude_hints.security_posture.strengthsandweaknessesin the summary
-
Executive Summary (3-4 paragraphs)
- Overall security posture
- Most critical risks and business impact
- Positive security controls detected
- Recommended immediate actions
-
Critical Findings with real-world attack scenarios
- For each critical/high finding: explain what an attacker could do
- Include curl PoC from the report
-
Root Cause Analysis
- Identify patterns (e.g., "missing auth middleware on 5 endpoints")
- Suggest systemic fixes, not just per-finding patches
- Use
claude_hints.critical_checksto highlight structural issues
-
Fix Priority Matrix
- Rank by exploitability x impact
- Quick wins vs architectural changes
- Reference the fix plan if generated
STOP HERE. Do NOT propose or apply fixes unless the user explicitly asks.
Part 2: FIX (only when user explicitly asks "fix the vulnerabilities")
CRITICAL RULE: Never fix anything unless the user explicitly requests it. Triggers: "fix", "fixe", "corrige", "applique les corrections", "patch", "remediate"
Step 6: Analyze Findings from Scan Report
Re-read the JSON report from Step 3. For each finding, extract:
severity,category,titleendpoint/ file locationremediationinstructionscwe_idfor fix pattern matching
Group findings by target file (the file that needs to be fixed).
Step 7: User Selection
Use AskUserQuestion with two questions:
Question 1 (single select): "How do you want to apply the fixes?"
- "Fix all" -- Apply all corrections at once
- "Select individually" -- Choose which fixes to apply
- "Preview only" -- Just review, don't fix anything
Question 2 (only if "Select individually"): Use multiSelect: true, one option per finding:
- Label:
[SEVERITY] Title - Description:
File: target_file | Category: category
Step 8: Deploy Fix Agents
Based on user selection, deploy Task agents in parallel:
Grouping rules:
- Group fixes targeting the same file into ONE agent
- Deploy agents for different files in parallel (single message, multiple Task calls)
- Each agent:
subagent_type: "general-purpose"
Agent prompt template:
Fix the following security issue(s) in the project at $ARGUMENTS.
File to modify: <target_file>
Fix 1: <title>
Severity: <severity>
Category: <category>
CWE: <cwe_id>
Remediation: <remediation>
Auth library context (from scan report):
- Library: <auth_profile.library>
- Session mechanism: <auth_profile.session_mechanism>
- Cookie names: <auth_profile.cookie_names>
- Middleware: <auth_profile.middleware_file>
IMPORTANT:
- Read the file first before making changes
- Make minimal, focused changes only
- Preserve existing code style and patterns
- Do NOT refactor surrounding code
- Use the existing auth patterns from the detected library
Fix types by category:
- Code vulnerabilities (auth, injection, XSS, IDOR) -> Agent edits the source file
- Config issues (CSP, headers, CORS) -> Agent edits the config file (next.config.ts, etc.)
- Environment variables -> Do NOT deploy an agent. Tell the user what env vars to set manually
- Dependency vulnerabilities -> Already handled by --fix-deps during the scan
proxy.ts vs middleware.ts detection:
- If
proxy.tsexists -> use it (Next.js 16+) - If
middleware.tsexists -> use it (older Next.js) - If neither -> check package.json Next.js version to decide
Step 9: Verification
After all fix agents complete, re-run SAST:
nextjs-pentestkit sast $ARGUMENTS
Compare before vs after:
- How many fixes were applied
- How many suspects were resolved
- Any remaining issues
- New score if full scan re-run
Auth Detection Reference
The scanner automatically detects 15+ auth libraries dynamically:
| Library | Detection | Endpoints | Session |
|---|---|---|---|
| Better Auth | better-auth in package.json |
/api/auth/sign-in/email |
Cookie (better-auth.session_token) |
| NextAuth v4 | next-auth in package.json |
/api/auth/callback/credentials |
Cookie (next-auth.session-token) |
| Auth.js v5 | @auth/core in package.json |
/api/auth/callback/credentials |
Cookie (authjs.session-token) |
| Clerk | @clerk/nextjs in package.json |
Clerk-hosted | Cookie (__session) |
| Supabase | @supabase/ssr in package.json |
/auth/v1/token |
Bearer token |
| Lucia | lucia in package.json |
Custom (dynamic discovery) | Cookie (auth_session) |
| Kinde | @kinde-oss/kinde-auth-nextjs |
/api/auth/login |
Cookie (kinde_token) |
| WorkOS | @workos-inc/authkit-nextjs |
WorkOS-hosted | Cookie (wos-session) |
| Stack Auth | @stackframe/stack |
/api/auth/sign-in |
Cookie |
| Firebase | firebase-admin in package.json |
Firebase-hosted | Bearer token |
| Passport | passport in package.json |
/auth/login (custom) |
Cookie (connect.sid) |
| Iron Session | iron-session in package.json |
Custom | Cookie (custom name) |
| Custom JWT | jsonwebtoken/jose imports |
Dynamic discovery | Bearer token |
| Custom Password | bcrypt/argon2 imports |
Dynamic discovery | Variable |
Dynamic fallback: If no known library is found in package.json, the scanner scans source code imports and config patterns to detect auth. This catches monorepos, custom setups, and libraries not yet in the database.
ORM detection: Prisma, Drizzle, Mongoose, TypeORM, Sequelize, Knex — schema is parsed for user tables and tenant fields.
Fix Rules
- Always read target files BEFORE editing
- Minimal changes only -- no refactoring
- Reuse the project's existing patterns (auth, rate limiting, etc.)
- Never modify .env files automatically -- tell user what to change
- Findings with FP >= 80% should be shown as likely false positives and skipped
- Findings with FP < 25% are high-confidence real issues
- If a fix seems risky, ask the user before applying
Verification System (for understanding scan results)
Every DAST finding goes through multi-step probing:
- Initial probe -- detect potential vulnerability
- Retry verification -- confirm consistent behavior (not a flake)
- Differential verification -- compare with legitimate request
- Cross-check -- verify response contains meaningful data
Confidence levels:
- CONFIRMED: all probes pass -> appears in report
- HIGH: strong indicators -> appears in report
- MEDIUM: heuristic match -> excluded by default
- LOW: possible false positive -> excluded
JWT tests (alg=none, role tampering, etc.) only run on bearer token auth systems. Cookie-based auth (Better Auth, NextAuth, Clerk, Lucia) -> JWT tests are auto-skipped.
Security Notice
This tool is for authorized security testing only. Always:
- Have written authorization before testing
- Use sandboxed environments
- Limit request rates (configurable with --max-rps)
- Never test production without explicit approval