audit-security — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited audit-security (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Audit all 33 security vectors, report findings with per-vector verdicts, and optionally fix. Works on any web project (Next.js, React, Express, Django, Go, etc.).
$ARGUMENTS — optional flags:--fix — fix all findings after audit--audit-only — report findings without fixing (this is the DEFAULT if no flags given)--scope=<path> — limit to specific directory (default: entire project)--report — save full report to _local/reports/security-audit-<YYYY-MM-DD>.md--skip-deps — skip dependency vulnerability check (vector 27)Default behavior: audit-only. Fixes are opt-in via --fix.
Read project files to identify the stack. This determines which vectors are relevant and which tools/commands to use.
| Check | How | Records |
|---|---|---|
| Language | package.json → Node/TS, requirements.txt/pyproject.toml → Python, go.mod → Go, Cargo.toml → Rust, Gemfile → Ruby | Primary language |
| Framework | next → Next.js, express → Express, fastify → Fastify, hono → Hono, django → Django, flask → Flask, gin → Gin | Framework name + version |
| Database | Grep for prisma, mongoose, sequelize, typeorm, pg, mysql2, sqlite3, redis in deps | DB type or "none" |
| Auth | Grep for next-auth, passport, clerk, auth0, supabase, firebase in deps | Auth library or "custom" or "none" |
| Has API routes | Glob for **/api/**/*.{ts,js,py,rb,go} or server action files | true/false |
| Has AI features | Grep for openai, anthropic, @ai-sdk, langchain in deps | true/false |
package.json scripts for build, lint, test, typecheckpytest, ruff, mypy in depsgo build ./..., go vet ./..., go test ./...cargo build, cargo clippy, cargo testRecord exact commands. If none found, note "no build/lint configured."
Mark each of the 33 vectors as RELEVANT or N/A based on detected stack:
N/A vectors still appear in the final report but with verdict "N/A — [reason]".
Every finding uses this format:
### Vector N: [Name] — [VERDICT]
- **Severity:** CRITICAL / HIGH / MEDIUM / LOW
- **Verdict:** Protected / Partially Protected / Not Protected / N/A
- **Evidence:** [file:line and what was found, or "no instances found"]
- **Current protection:** [what's already in place, if anything]
- **Gap:** [what's missing]
- **Fix:** [concrete remediation steps]VERDICT rules:
CRITICAL RULE: Only assign verdicts based on evidence found via Grep/Glob/Read. If you cannot verify a vector from the codebase (e.g., DNS records, WAF config, infrastructure settings), report it as: "Cannot verify from code — requires infrastructure review" and do NOT assign Protected/Not Protected.
Launch ALL four agents concurrently using the Agent tool. Pass each agent: project path, scope, detected stack, and relevant vector numbers.
Agent tool prompt:
Audit web application security vectors in the project at [cwd]. Scope: [scope]. Stack: [stack summary].
>
For each vector below, search the codebase using Grep/Glob and report findings using this format: ### Vector N: Name — [Protected|Partially Protected|Not Protected|N/A] with Severity, Verdict, Evidence, Current protection, Gap, and Fix fields.>
Vector 1 — XSS: - Grep for:dangerouslySetInnerHTML,innerHTML\s*=,v-html,\[innerHTML\]- For each instance: trace the data source. Static/hardcoded = Protected. External data with sanitization (DOMPurify, sanitize-html) = Protected. External data WITHOUT sanitization = Not Protected (CRITICAL). - Search config files for Content-Security-Policy header. Check forunsafe-inline,unsafe-eval(these weaken CSP). - If framework auto-escapes (React JSX, Vue templates, Angular) and no bypass found = Protected.
>
Vector 2 — CSRF: - Find all POST/PUT/DELETE endpoints: Grep forexport.*POST,app.post,router.post,@app.route.*POST- For each: check if it validates Origin header (request.headers.get("origin")) or uses CSRF tokens - Check cookies forsameSiteattribute - Django: checkCsrfViewMiddlewareis in MIDDLEWARE and not bypassed (@csrf_exempt)
>
Vector 3 — Clickjacking: - Search config forX-Frame-Optionsandframe-ancestorsin CSP - If both missing = Not Protected
>
Vector 4 — SQL/NoSQL Injection: [SKIP if no database detected] - Grep for string concatenation in queries:query(\,query("++,.raw(,$where- Grep for parameterized queries:query($1),?placeholders, ORM methods - If only ORM with no.raw()` usage = Protected
>
Vector 5 — Command Injection: - Grep for:child_process,exec(,execSync,spawn(,system(,subprocess,os.system- For each: check if user input flows into the command. Shell commands with hardcoded strings = LOW.
>
Vector 6 — SSRF: - Find server-side fetch/request calls that accept URLs from user input (query params, request body) - Check for IP/hostname blocklists - If no server-side URL fetching from user input exists = N/A
>
Vector 7 — Open Redirect: - Grep forredirect(,res.redirect(,location.href =where URL comes from user input - Check for hostname validation or allowlist
>
Vector 8 — Path Traversal: - Grep forfs.readFile,fs.createReadStream,open(,Path.joinwith user input - Check for../sanitization - If no file operations with user input = N/A
>
Vector 9 — HTTP Parameter Pollution: - Check if request handling validates payload schema (Zod, Joi, Yup, class-validator) - If using typed schema validation = Protected
>
Vector 10 — XXE: [SKIP if no XML parsing] - Grep for XML parsing:xml2js,DOMParser,lxml,xml.etree- Check if external entity processing is disabled - If no XML parsing = N/A
>
End with findings summary block: ---FINDINGS-SUMMARY--- with critical/high/medium/low counts.Agent tool prompt:
Audit authentication and session security in the project at [cwd]. Scope: [scope]. Stack: [stack summary]. Auth system: [detected auth library or "custom" or "none"].
>
If no auth system detected: report all 5 vectors as N/A with note "No authentication system found." and STOP.
>
For each vector, search the codebase and report findings.
>
Vector 11 — Brute Force: - Find auth endpoints: Grep for login, register, password-reset, invite routes - For each: check for rate limiting (in-memory Map, Redis, express-rate-limit, django-ratelimit) - Check if rate limiter fails closed (returns error when unavailable, not silently passes)
>
Vector 12 — Session Fixation: - Check if sessions are regenerated after login (Grep forregenerate,rotate, new session creation post-auth) - Check for session IDs in URLs
>
Vector 13 — Session Hijacking: - Find all cookie-setting code. Check flags:httpOnly,secure,sameSite- Grep for auth tokens inlocalStorage(should be httpOnly cookies instead) - Grep for session data in URL parameters
>
Vector 14 — Credential Stuffing: - Check for account-level rate limiting (not just IP-based) - Check for MFA support - Check password complexity requirements
>
Vector 15 — Broken Authentication: - Check middleware/guard coverage: find the auth middleware, then check if all routes are covered (look for unprotected routes) - Grep for===comparison on secrets (should usetimingSafeEqualorhmac.compare_digest) - Grep forMath.randomin auth context (should usecrypto.randomBytes) - Grep for secrets in URL query params
>
End with findings summary block.
Agent tool prompt:
Audit API and infrastructure security in the project at [cwd]. Scope: [scope]. Stack: [stack summary].
>
For each vector, search the codebase and report findings. Vectors that require infrastructure access (DNS, WAF, CDN config) should be reported as "Cannot verify from code — requires infrastructure review."
>
Vector 16 — API Rate Limiting: - Find all public API endpoints. Check for rate limiting on each. - Flag expensive operations (AI calls, file uploads, email sending) without strict limits.
>
Vector 17 — Mass Assignment: - Grep forObject.assign(,...req.body,Object.fromEntries(spreading user input into objects without field allowlisting - Check for Zod/Joi schema parsing (.parse()or.validate()) which provides allowlisting = Protected
>
Vector 18 — Broken Object-Level Authorization: - Check CRUD endpoints: do they verify the requesting user owns the resource? - Look for resource access by ID without ownership check
>
Vector 19 — Excessive Data Exposure: - Grep forcatchblocks that returnerror.messageorerror.stackto the client - Check API error responses for internal details
>
Vector 20 — DoS: - Check for request body size limits on POST endpoints - Grep for regex patterns and check for catastrophic backtracking (nested quantifiers:(a+)+,(a|b)*c) - Check for timeouts on external API calls (AbortSignal.timeout,signal, request timeout config)
>
Vector 21 — DNS Rebinding: Cannot verify from code. Report: "Requires infrastructure review — check DNS resolver and SSRF protections for TOCTOU."
>
Vector 22 — HTTP Request Smuggling: If using standard framework (Express, Next.js, Django, etc.) = Protected (framework handles parsing). Only flag if manual HTTP parsing found.
>
Vector 23 — Man-in-the-Middle: - Check for HSTS header - Grep forhttp://in fetch/request calls to external APIs (should behttps://) - Check cookiesecureflag
>
Vector 24 — Subdomain Takeover: Cannot verify from code. Report: "Requires DNS audit — check CNAME records for dangling references."
>
Vector 25 — Security Headers: - Search all config/middleware for each header: CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy - For each: report found (with value) or missing
>
End with findings summary block.
Agent tool prompt:
Audit client-side and AI security in the project at [cwd]. Scope: [scope]. Stack: [stack summary]. Has AI features: [true/false].
>
Vector 26 — Prototype Pollution: - Grep forObject.assign(,_.merge(,deepMerge(where first argument receives user data - Grep forJSON.parse(on user-controlled strings without schema validation after - Check for__proto__orconstructorsanitization
>
Vector 27 — Supply Chain Attack: - Check if lockfile exists:package-lock.json,yarn.lock,pnpm-lock.yaml,Pipfile.lock,go.sum,Cargo.lock- Grep for external<script src="httpor<link href="httpwithoutintegrity=attribute - Note: recommend runningnpm audit/pip-audit/cargo auditbut do NOT run it (may require network). Report as "Recommendation: run [command]." - If--skip-depsflag was passed, skip this vector entirely and mark N/A.
>
Vector 28 — Dependency Confusion: - Check for.npmrcor.yarnrcscoped registry config - Check if private package names (frompackage.jsonname field) could conflict with public registry - If package name is scoped (@company/name) = lower risk - If no private packages = N/A
>
Vector 29 — Browser Cache Poisoning: - Check Cache-Control headers on API endpoints (sensitive endpoints should useno-store) - Check forVaryheaders on personalized responses
>
Vector 30 — Tabnabbing: - Grep fortarget="_blank"ortarget='_blank'— check forrel="noopener noreferrer"(orrel="noopener"at minimum) - React 19+ and modern browsers auto-add noopener, so this is LOW in modern stacks
>
Vectors 31-33 — AI Security: [SKIP ALL if no AI features detected — report as N/A]
>
Vector 31 — Prompt Injection: - Grep for AI SDK calls:openai.chat,anthropic.messages,generateText,streamText- For each: trace if user input is interpolated into the prompt. Check for sanitization (strip control chars, limit length).
>
Vector 32 — AI Data Poisoning: - Check if AI responses are cached (in DB, Redis, localStorage). If cached: check for schema validation on read.
>
Vector 33 — Model Extraction: - Check if AI error responses leak model names or versions - Grep for model name strings in client-side code
>
End with findings summary block.
After all four agents return:
# Security Audit Report — [Project Name]
**Date:** YYYY-MM-DD | **Scope:** [path] | **Stack:** [detected]
## Scorecard: X/33 vectors assessed, Y protected
| # | Vector | Verdict | Severity | Evidence |
|---|--------|---------|----------|----------|
| 1 | XSS | Protected | — | CSP strict, no dangerouslySetInnerHTML |
| 2 | CSRF | Not Protected | CRITICAL | No origin check on POST /api/contact |
| ... | ... | ... | ... | ... |
| 33 | Model Extraction | N/A | — | No AI features |
## Findings by Severity
### Critical
[all critical findings with file:line]
### High
[all high findings]
### Medium / Low
[grouped]
## Infrastructure Review Needed
[vectors that cannot be verified from code]
## Recommendations
[dep audit commands to run, WAF config suggestions, etc.]--report flag is set.If --fix was passed:
Do NOT blindly apply TypeScript/Next.js patterns. Match fixes to the detected stack:
For Node.js/TypeScript projects: use the patterns below. For Python/Django projects: use Django equivalents (middleware, decorators, Django forms). For Go projects: use Go standard library equivalents. For other stacks: read framework docs and apply idiomatic fixes.
Timing-safe comparison:
import { timingSafeEqual } from 'crypto';
const a = Buffer.from(userValue, 'utf8');
const b = Buffer.from(expectedValue, 'utf8');
if (a.length !== b.length || !timingSafeEqual(a, b)) { /* reject */ }Origin validation:
const origin = request.headers.get("origin");
const host = request.headers.get("host");
if (origin && host && !origin.includes(host)) {
return Response.json({ error: "Forbidden" }, { status: 403 });
}Rate limiting (in-memory):
const RATE_LIMIT = new Map<string, { count: number; resetAt: number }>();
function checkRateLimit(ip: string, max: number, windowMs: number): boolean {
const now = Date.now();
const entry = RATE_LIMIT.get(ip);
if (!entry || now > entry.resetAt) {
RATE_LIMIT.set(ip, { count: 1, resetAt: now + windowMs });
return true;
}
if (entry.count >= max) return false;
entry.count++;
return true;
}Security headers (Next.js):
headers: [
{ key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=(self)" },
]Cookie hardening:
{ httpOnly: true, secure: true, sameSite: "strict", path: "/" }Run the build/lint/test commands detected in Setup:
If no build/lint/test commands were detected, skip verification and note: "No build/test commands found — manual verification recommended."
Update the report with fixes applied:
## Fixes Applied
| Vector | Finding | Fix | File(s) Changed |
|--------|---------|-----|-----------------|
| 2 | No CSRF check | Added origin validation | src/app/api/contact/route.ts |
## Updated Scorecard
Protected: X/33 (was Y/33 before fixes)Print the updated scorecard to the conversation.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.