From auto-audit
Scans workspace for security vulnerabilities using LLM code review and CLI scanners (npm audit, pip-audit, secret regexes). Outputs findings as JSON for auto-audit queue.
How this skill is triggered — by the user, by Claude, or both
Slash command
/auto-audit:audit-securityThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are performing a **security-focused** audit of the repo at the active auto-audit workspace. Your output is a **JSON array of findings** that gets fed to `add-findings.sh`, which dedupes and persists them.
You are performing a security-focused audit of the repo at the active auto-audit workspace. Your output is a JSON array of findings that gets fed to add-findings.sh, which dedupes and persists them.
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/common.sh"
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/state.sh"
WORKSPACE="$(workspace_dir)"
cd "$WORKSPACE"
Detect the stack with a few cheap checks (in parallel via a single bash call where possible):
test -f package.json && jq -r .name package.jsontest -f requirements.txt || test -f pyproject.tomltest -f go.modtest -f composer.jsontest -f Gemfiletest -f Cargo.tomlgit log --oneline -20 for recent activityRecord what you find in one short paragraph and choose which scanners apply.
Run the scanners that apply. For each, capture output and convert to findings.
if [ -f package.json ]; then
npm audit --json 2>/dev/null || true
fi
Parse the output. Each advisory with severity high or critical becomes a finding:
module: "security"category: "dependency-cve"severity: map npm's level to the plugin's enum — moderate → medium; low, high, critical pass through unchanged. The plugin does not recognise moderate and will rank it last if emitted raw.title: "Vulnerable dependency: <name>@<range> — <cve>"file: "package.json", line: 0description: include the advisory URL + recommended rangeif command -v pip-audit >/dev/null && [ -f requirements.txt -o -f pyproject.toml ]; then
pip-audit --format json 2>/dev/null || true
fi
Same mapping.
Raw grep -r over the workspace is blocked on some hosts by secret-leak hooks. Use the Grep tool directly — it runs ripgrep under the hood, faster, safer. Run each pattern as its own Grep call with path: $(workspace_dir), output_mode: "content", and a glob that excludes the usual vendored dirs.
Patterns to check (run each as a separate Grep call):
AKIA[0-9A-Z]{16} — AWS access key idghp_[A-Za-z0-9]{36} — GitHub personal access tokengho_[A-Za-z0-9]{36} — GitHub oauth tokensk-ant-[A-Za-z0-9_-]{20,} — Anthropic api keyxox[baprs]-[A-Za-z0-9-]{10,} — Slack token-----BEGIN (RSA\|OPENSSH\|EC\|DSA) PRIVATE KEY----- — private key pemAny hit becomes a critical/secrets finding. Exclude obvious fakes: placeholders in *.example, *.sample, test fixtures, and the well-known AKIAIOSFODNN7EXAMPLE placeholder from AWS docs.
This is where real bugs come from. Proceed in batches to keep per-prompt context manageable.
Use Glob to find files by category, bounded to reasonable sizes (skip huge generated files):
**/routes/**, **/controllers/**, **/api/**, **/handlers/**, **/pages/api/** (Next.js), **/app/**/route.{ts,js} (Next.js app router)auth|session|token|jwt|passport|login|signin|signup|register|password|oauthdb|database|query|repo|repository|dao|model|schema|migrations|sqlcrypto|hash|encrypt|decrypt|sign|verify|keypair|secrettemplate|render|view|html (XSS risk)upload|file|fs|download|export|importparse|deserial|unmarshal|yaml\.load|pickle\.loadexec, spawn, child_process, subprocess.call, os.system, eval, Function(, setTimeout(string)Glob each pattern, filter to files < 1500 lines and not in node_modules|vendor|dist|build|.next|target. Collect into buckets.
For each bucket, pick up to ~10 files. Read them with parallel Read tool calls (one file_path per call — issue them in a single turn so they run concurrently). For each file, look for the bug classes relevant to that bucket:
| Bucket | Bug classes to look for |
|---|---|
| Routes | Missing auth, IDOR, mass assignment, SSRF, open redirect, prototype pollution, rate-limit gaps |
| Auth | Weak session config, missing csrf, insecure cookie flags, timing attacks on compare, password policy, OAuth state missing, JWT alg=none/none confusion, refresh-token replay |
| Database | SQLi (string-concat queries), unparameterised raw queries, ORM misuse (findOne w/ user input as full filter), missing tenant isolation, TOCTOU |
| Crypto | Weak algo (MD5/SHA1 for auth, ECB), hardcoded keys/IVs, Math.random() for secrets, missing HMAC verification, predictable tokens |
| Templating | Unescaped user input (dangerouslySetInnerHTML, v-html, {{{ }}}, safe filters), template injection |
| Upload/FS | Path traversal (../), untrusted zipfile extraction (zip-slip), unrestricted file type, symlink attacks |
| Deserialization | Unsafe YAML/pickle/java-serialization, prototype pollution via Object.assign/merge, XXE |
| Shell/exec | Command injection (user input in shell string), unsafe eval, VM2/node vm escape patterns |
Be specific. For each real vulnerability, extract:
Prefer recall over precision. Emit a finding whenever you can trace a plausible path from untrusted input to a dangerous sink — the triage subagent later will reject anything not truly exploitable. Skip a finding only when you can already describe why it is not reachable; do not sit on borderline cases.
After each batch, write out an array of findings to a temp file, then append:
FINDINGS_TMP="$(mktemp --suffix=.json)"
cat > "$FINDINGS_TMP" <<'JSON'
[
{
"module": "security",
"category": "injection",
"severity": "high",
"title": "SQL injection in search endpoint",
"file": "src/routes/search.ts",
"line": 42,
"description": "The `q` query parameter is concatenated directly into a raw SQL string on line 42. An attacker can append `' OR 1=1 --` to dump arbitrary rows. No parameterisation, no allowlist.",
"code_snippet": "const rows = await db.query(`SELECT * FROM items WHERE name LIKE '%${req.query.q}%'`);"
}
]
JSON
bash "${CLAUDE_PLUGIN_ROOT}/scripts/add-findings.sh" < "$FINDINGS_TMP"
rm -f "$FINDINGS_TMP"
The script dedupes against existing findings (same file+line+title).
The orchestrator (/auto-audit:start or the tick rescan) requires the last line of stdout to be findings_added=<integer>. Count what was actually added by diffing stats.discovered before and after the scan, or just count the lines add-findings.sh emitted (one id per added finding). Emit the summary for humans above that contract line:
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/state.sh"
echo "security scan complete: $(stats | jq -c .)"
echo "findings_added=${ADDED_COUNT:-0}"
Keep $ADDED_COUNT tracked across the batches in Phase C (accumulate the number of non-blank lines returned from each add-findings.sh invocation).
scan-cursor.json) are a roadmap item; this version re-scans from scratch each rescan and relies on add-findings.sh to dedupe.npx claudepluginhub wrxck/claude-plugins --plugin auto-auditScans codebases for vulnerabilities like SQL injection, XSS, auth flaws, insecure deps, and secrets using grep and bash. Generates severity-rated reports with file locations, explanations, and fixes.
Scans codebases for leaked secrets (API keys, tokens, passwords, private keys), insecure code patterns, and configuration issues. Returns severity-rated findings with file locations and remediation steps.