Security audits with Claude Code
A security audit with Claude Code pairs deterministic scanners (Gitleaks, TruffleHog, npm audit) with three Claude reviewers: the built-in /security-review command for a branch diff, the Claude Security plugin for a verified whole-repository scan with patch files, and the security-guidance plugin while code is written. A failing exploit test proves each accepted finding.
A pen-test report lands with 18 findings, six of them critical: SQL injection in the admin API, a JWT secret committed two years ago, and a dependency with a published remote-code-execution advisory. You have a compliance review next month and a team that ships most of its code through agents. You need to know what is real, fix it without breaking behaviour, and stop the same classes from coming back. This page is for the developer who runs the audit and the tech lead who owns the gates afterwards.
What you’ll walk away with from a Claude Code security audit
Section titled “What you’ll walk away with from a Claude Code security audit”- A six-step audit order you can run on any repository this week, from secret containment to CI gates.
- Copy-paste prompts for dependency reachability triage, history-wide secret sweeps and exploit-test-first fixes.
- A rule for accepting a finding that does not require anyone to read the whole diff: no failing exploit test, no fix.
- A
CLAUDE.mdsecurity block, aclaude-security-guidance.mdpolicy file and a GitHub Actions job you can commit as-is.
Which Claude Code security tool fits which job?
Section titled “Which Claude Code security tool fits which job?”Claude Code ships several security features, and they are easy to confuse. They differ in scope, cost and whether a finding has been independently checked. Checked against Claude Code 2.1.283 (the latest channel) and the plugin READMEs on 2026-09-26.
| Tool | What it scans | When to use it | What you get |
|---|---|---|---|
/security-review (built-in) | The diff between your branch and origin/HEAD | Before every PR that touches auth, input handling or data access | Findings in the session: injection, auth issues, data exposure |
Claude Security plugin (/claude-security) | The whole repository, a scoped part of it, a branch diff, a pull request or one commit | The first audit, then periodically | A CLAUDE-SECURITY-<timestamp>/ report in Markdown, JSONL and SARIF 2.1.0, plus optional patch files |
| security-guidance plugin | Every edit, every finished turn, and every git commit and git push | Always on for teams that let agents write most of the code | Findings fed back to Claude before you see its answer |
anthropics/claude-code-security-review GitHub Action | Each pull request | CI, on trusted PRs only | Inline PR comments and a results artifact |
Gitleaks, TruffleHog, npm audit, Semgrep | Secrets, known-vulnerable packages, rule-based patterns | Every commit and every CI run | Deterministic, repeatable results |
/code-review is a correctness reviewer, not a security scanner; the automated code review guide covers it, along with Ultrareview and managed Code Review. Semgrep, Snyk, SonarQube and the other scanners you can put around an agent are compared in security gates for agent-written code.
How to run a Claude Code security audit, step by step
Section titled “How to run a Claude Code security audit, step by step”The order matters. Containment comes before discovery, because a leaked key is being abused while you read the report. Deterministic scanners come before the model, because their output is ground truth the model can reason about instead of guessing.
-
Keep secrets out of the session. Before Claude reads the repository, deny it the files that hold live credentials. Add this to
.claude/settings.json(the project settings file):{"permissions": {"deny": ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"]}}To audit a repository you do not trust, such as a third-party dependency, run the whole session inside Anthropic’s sandbox-runtime. The Claude Security plugin adds no isolation of its own: the repository’s
.claude/hooks andCLAUDE.mdapply as in any other session. -
Run the deterministic scanners and keep their output. In a terminal at the repository root:
Terminal window gitleaks git --report-path gitleaks-report.json # secrets in full git historytrufflehog git file://. --results=verified,unknown # checks secrets against the issuing servicenpm audit --omit=dev --json > npm-audit.json # advisories in production dependenciessemgrep scan --config auto --json -o semgrep.json # rule-based patterns; auto sends your project URL to the Semgrep RegistryAny secret TruffleHog reports as
verifiedis live. Rotate it now, before anything else on this page. -
Install the Claude Security plugin and scan the codebase. In the Claude Code prompt:
/plugin install claude-security@claude-plugins-official/reload-plugins/claude-securityThe menu offers Scan codebase, Scan changes and Suggest patches. You can skip it with a plain request such as
run a quick Claude Security scan on the whole repo. The scan states its time and token cost and asks you to confirm once. It needs Python 3.9 or newer onPATH. The plugin README recommends Claude Opus 5.5 or Claude Fable 5.1 (see the models hub), and warns that its cyber safeguards may run parts of a scan on Opus 4.8.Every candidate finding goes to verifier agents told to disprove it; only survivors reach
CLAUDE-SECURITY-RESULTS.md. Every top-level directory is either scanned or set aside with a reason, and the report’s Coverage section names whatever was left out and why, so a clean result tells you what was examined. -
Triage the dependency advisories by reachability.
npm auditreports what is installed, not what your code calls. Hand Claude the saved report and ask for exposure analysis (prompt below). Advisories in code your application never reaches go on a tracked backlog, not into this week’s work. -
Fix with an exploit test first. For each accepted finding, Claude writes a test that demonstrates the exploit and fails against the current code, then the fix, then shows the test passing. Claude Security’s Suggest patches job writes one
F<n>.patchper finding underCLAUDE-SECURITY-<timestamp>/patches/and applies nothing itself. Review the note beside each patch, then apply it withgit apply CLAUDE-SECURITY-<timestamp>/patches/F1.patch. -
Lock the gates so the classes stay fixed. Add the
CLAUDE.mdrules and the security-guidance plugin described below, make/security-reviewpart of your pre-PR routine, and put Gitleaks and the security-review Action in CI.
Copy-paste prompts for a security audit
Section titled “Copy-paste prompts for a security audit”Use the first prompt when you cannot install the plugin, for example on a locked-down enterprise install. It asks for the same evidence the plugin demands: an exploit path, not a pattern match.
How do you verify security fixes without reading every line?
Section titled “How do you verify security fixes without reading every line?”The audit is only useful if you can accept its output on evidence. These checks replace line-by-line review of each fix:
| Evidence | What it proves | Who signs off |
|---|---|---|
| Exploit test that failed before the fix and passes after | The finding was real and is closed | The developer who owns the module |
| Full test suite green | The fix did not change legitimate behaviour | CI |
Gitleaks and npm audit --audit-level=high clean in CI | No new secrets or high-severity advisories | CI, as a required check |
| SARIF uploaded to GitHub code scanning | Findings are tracked across scans; the stable claudeSecurityPluginFindingId tells new findings from known ones | Tech lead reviews the open list weekly |
CLAUDE-SECURITY-REVISION-<sha12>.json | Which commit was scanned, at what effort, and how thoroughly it was verified | Attached to the audit record |
| Suppression with a written reason | A false positive was judged, not ignored | Tech lead or security owner |
The Claude Security scan runs on your machine, so nothing uploads its SARIF for you. Commit the report directory to an audit branch and add a workflow step that uses github/codeql-action/upload-sarif with sarif_file: CLAUDE-SECURITY-<timestamp>/CLAUDE-SECURITY-RESULTS.sarif; without code scanning, archive the SARIF with the audit record instead.
A human still reads two things: the exploit test (does it attack what the finding describes?) and every suppression. Both are short. The fix itself is judged by the test, the suite and the rescan.
Encode security rules so every future change follows them
Section titled “Encode security rules so every future change follows them”CLAUDE.md shapes what Claude writes; the security-guidance plugin checks what it wrote. Use both. Start with a block like this in the project CLAUDE.md (see the memory system guide for where it loads):
## Security requirements
- Database access goes through the ORM or parameterized queries. Never build SQL with string concatenation or template literals.- Every route requires the auth middleware except this list: /health, /ready, /api/auth/login, /api/auth/register.- Passwords are hashed with argon2id or bcrypt (cost 12). Never MD5 or SHA-family hashes for passwords.- All request bodies, query parameters and path parameters are validated with Zod schemas before use.- Secrets come from environment variables. Never commit a credential, including in tests or fixtures.- Outbound HTTP to a user-supplied URL goes through src/lib/net/safe-fetch.ts (SSRF allowlist).- A security fix ships with a test that performs the exploit.Then install the security-guidance plugin, which runs as hooks and adds no always-on context:
claude plugin install security-guidance@claude-plugins-officialIt has three layers: regex warnings on about 25 dangerous patterns at each Edit/Write, an LLM review of the diff when Claude finishes a turn, and an agentic reviewer on git commit and git push that traces data flow across files. It needs Claude Code 2.1.144 or later and Python 3.8 or later. The diff review defaults to claude-opus-4-7; set SECURITY_REVIEW_MODEL (and SG_AGENTIC_MODEL for the commit reviewer) to change it, using your provider’s model ID on Bedrock or Google Cloud. Rules specific to your codebase go in .claude/claude-security-guidance.md, committed with the repository:
# Payments API security rules
- Reads from the customers and orders tables use db.replica, never db.primary.- Background jobs never use a user's auth token; they call jobs.getServiceAccount().- Any fetch() with a user-controlled URL must use safeFetch() from src/lib/net/safe-fetch.ts.The file has an 8 KB budget and is sent to the model on every review, so keep secrets out of it. Its commit-time reviewer does not read this file yet (plugin README, 2026-09-26).
Add a security review gate to CI
Section titled “Add a security review gate to CI”Run the deterministic scanner as the required check and the Claude reviewer as advice on each PR. Only the review job can write PR comments. Save this as .github/workflows/security.yml:
name: Securityon: pull_request:permissions: contents: readjobs: secrets: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: 0 - uses: gitleaks/gitleaks-action@v3 # v2 ran on Node 20, which GitHub-hosted runners have dropped env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} # free key; required for organization-owned repos claude-review: runs-on: ubuntu-latest permissions: contents: read pull-requests: write # only this job posts PR comments steps: - uses: actions/checkout@v7 with: persist-credentials: false ref: ${{ github.event.pull_request.head.sha || github.sha }} fetch-depth: 2 # Pin to a full commit SHA instead of @main before relying on this job - uses: anthropics/claude-code-security-review@main with: comment-pr: true claude-api-key: ${{ secrets.CLAUDE_API_KEY }} claude-model: claude-opus-5-5 # the built-in default is claude-opus-4-1-20250805, retired on the Claude APITwo lines in that file are not optional. The Action’s own default model is claude-opus-4-1-20250805, and Claude Opus 4.1 has been retired on the Claude API, so a workflow copied from the Action’s quick start without claude-model has nothing to run on (current model IDs are on the models hub). And gitleaks-action@v2 ran on Node 20; its README (checked 2026-09-26) moves to @v3 with actions/checkout@v6 because GitHub is removing Node 20 from its hosted runners in September 2026. This page pins actions/checkout@v7, the current major (v7.0.1, checked 2026-10-03). The claude-api-key must be enabled for both the Claude API and Claude Code.
The Action’s README states it is not hardened against prompt injection. In a public repository, turn on Require approval for all external contributors so the job runs only after a maintainer has looked at the PR. The CI/CD pipeline guide covers secrets and pinning, and scheduled security scans covers running a read-only scan on a schedule with retained evidence.
When a Claude Code security audit goes wrong
Section titled “When a Claude Code security audit goes wrong”/security-review stops with fatal: ambiguous argument 'origin/HEAD...'. The command diffs against origin/HEAD, which single-branch and CI checkouts often lack. Run git fetch origin and git remote set-head origin --auto, or name the branch with git remote set-head origin main, then rerun.
The security-review job fails before it posts anything. Check the job log for a model error first: without claude-model the Action asks for claude-opus-4-1-20250805, which the Claude API no longer serves. Set claude-model as in the workflow above. If the log instead shows a Node runtime error on the Gitleaks step, move to gitleaks/gitleaks-action@v3.
Two scans report different findings. Model-based scans are nondeterministic. Track findings by claudeSecurityPluginFindingId in code scanning instead of comparing reports by eye, and schedule scans so coverage builds over time.
Claude flags a route as unauthenticated that is public by design. Add it to the public-routes list in CLAUDE.md. For the security-guidance plugin, an inline comment explaining why the line is safe is treated as an exclusion. For the Action, point false-positive-filtering-instructions at a text file of your accepted patterns.
A patch closes the finding but breaks legitimate requests. The Claude Security patch review counts a change in accepted inputs as a behaviour change and says when no project test exercised the patched code. Treat that note as a missing test: write one for the legitimate case before applying.
The dependency upgrade breaks the build. Ask for the changelog analysis in the reachability prompt before upgrading, and upgrade one major version per commit so a failing suite points at one package.
A strict Content-Security-Policy breaks the frontend. Ship it as Content-Security-Policy-Report-Only first, collect the violations from the browser console or your report endpoint, and paste them back to Claude to allow exactly those sources.
The Stop-hook review fires on another agent’s work. In shared-worktree setups where several agents move HEAD, set ENABLE_STOP_REVIEW=0 and keep the commit and push reviews.
A report or log holds a credential. Claude Security redacts credential values in its reports as a best effort, and its report directory carries its own .gitignore. Check the files before you share them.
Where to go next after a security audit
Section titled “Where to go next after a security audit”The same audit in the sibling tools: security audits with Codex, Codex Security and security in Cursor. Back to the Operate section overview.