Skip to content

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.md security block, a claude-security-guidance.md policy 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.

ToolWhat it scansWhen to use itWhat you get
/security-review (built-in)The diff between your branch and origin/HEADBefore every PR that touches auth, input handling or data accessFindings 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 commitThe first audit, then periodicallyA CLAUDE-SECURITY-<timestamp>/ report in Markdown, JSONL and SARIF 2.1.0, plus optional patch files
security-guidance pluginEvery edit, every finished turn, and every git commit and git pushAlways on for teams that let agents write most of the codeFindings fed back to Claude before you see its answer
anthropics/claude-code-security-review GitHub ActionEach pull requestCI, on trusted PRs onlyInline PR comments and a results artifact
Gitleaks, TruffleHog, npm audit, SemgrepSecrets, known-vulnerable packages, rule-based patternsEvery commit and every CI runDeterministic, 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.

  1. 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 and CLAUDE.md apply as in any other session.

  2. 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 history
    trufflehog git file://. --results=verified,unknown # checks secrets against the issuing service
    npm audit --omit=dev --json > npm-audit.json # advisories in production dependencies
    semgrep scan --config auto --json -o semgrep.json # rule-based patterns; auto sends your project URL to the Semgrep Registry

    Any secret TruffleHog reports as verified is live. Rotate it now, before anything else on this page.

  3. Install the Claude Security plugin and scan the codebase. In the Claude Code prompt:

    /plugin install claude-security@claude-plugins-official
    /reload-plugins
    /claude-security

    The 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 on PATH. 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.

  4. Triage the dependency advisories by reachability. npm audit reports 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.

  5. 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>.patch per finding under CLAUDE-SECURITY-<timestamp>/patches/ and applies nothing itself. Review the note beside each patch, then apply it with git apply CLAUDE-SECURITY-<timestamp>/patches/F1.patch.

  6. Lock the gates so the classes stay fixed. Add the CLAUDE.md rules and the security-guidance plugin described below, make /security-review part of your pre-PR routine, and put Gitleaks and the security-review Action in CI.

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:

EvidenceWhat it provesWho signs off
Exploit test that failed before the fix and passes afterThe finding was real and is closedThe developer who owns the module
Full test suite greenThe fix did not change legitimate behaviourCI
Gitleaks and npm audit --audit-level=high clean in CINo new secrets or high-severity advisoriesCI, as a required check
SARIF uploaded to GitHub code scanningFindings are tracked across scans; the stable claudeSecurityPluginFindingId tells new findings from known onesTech lead reviews the open list weekly
CLAUDE-SECURITY-REVISION-<sha12>.jsonWhich commit was scanned, at what effort, and how thoroughly it was verifiedAttached to the audit record
Suppression with a written reasonA false positive was judged, not ignoredTech 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:

Terminal window
claude plugin install security-guidance@claude-plugins-official

It 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).

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: Security
on:
pull_request:
permissions:
contents: read
jobs:
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 API

Two 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.

The same audit in the sibling tools: security audits with Codex, Codex Security and security in Cursor. Back to the Operate section overview.