Claude Code as a Security Scanner: Beyond Pattern Matching
Tools like ESLint, Semgrep, and Bandit catch what they are programmed to find: known patterns, common injection strings, deprecated API calls. They are fast, reliable, and deterministic. They are also blind to anything that requires understanding what your code is supposed to do.
Claude Code operates differently. It reads code the way a human security researcher would — tracing data flows across files, understanding business logic, and reasoning about what could go wrong given the specific context of your application. This makes it effective at a class of vulnerabilities that pattern-matching tools routinely miss.
What Traditional Scanners Cannot Find
flowchart TD
subgraph Traditional[Traditional Static Analysis]
P1[Known injection patterns]
P2[Deprecated API calls]
P3[Common misconfigurations]
P4[Syntax-level issues]
end
subgraph Claude[Claude Code Analysis]
C1[Business logic flaws]
C2[IDOR vulnerabilities]
C3[Multi-step workflow exploits]
C4[Cross-file data flow issues]
C5[Auth state inconsistencies]
end
Traditional -->|misses| Claude
Business logic flaws are the hardest category to catch with automation. Consider a scenario where a discount code is validated at checkout but stored in the session — and the session persists across authentication state changes. A scanner looking for SQL injection will not find this. Claude, reading the checkout flow end-to-end, can trace the discount code from validation through storage through redemption and flag that the code survives logout.
IDOR vulnerabilities (Insecure Direct Object References) require understanding the relationship between your URL parameters and your data model. A route that accepts /api/orders/:id without checking that the authenticated user owns that order is exploitable — but only if the scanner understands what “owns” means in your domain.
Multi-step workflow exploits — broken password resets, email verification bypasses, payment state mismatches — require following a complete user journey across multiple endpoints, often across multiple files.
How to Run a Security Audit
Option 1: Direct prompt
For a specific file or component:
Audit src/api/checkout.ts for security vulnerabilities.
Trace data flows end to end — follow the cart data from the request through
validation, pricing, discount application, and payment processing.
Look specifically for:
- Auth and authorization gaps (can an unauthenticated user reach any step?)
- State that persists across user sessions incorrectly
- Places where user-supplied values touch database queries or file paths
- Business logic that could be exploited (price manipulation, discount reuse)
For each finding: severity (critical/high/medium/low), exact location,
and why it is exploitable in this specific codebase.
Option 2: Custom slash command
Create .claude/commands/security-audit.md in your project:
Review $ARGUMENTS for security vulnerabilities.
Trace data flows end-to-end across related files — not just the file provided.
Check for:
- Injection risks: SQL, command injection, path traversal
- Authentication and authorisation gaps
- Sensitive data exposure in logs or responses
- Business logic flaws specific to this application's domain
- Insecure Direct Object References
- Multi-step workflow vulnerabilities
Rate each finding: critical / high / medium / low
Include: file path, line number, description, and why it is exploitable.
Do not make any code changes — report only.
Then run it:
/project:security-audit src/api/payments/
The Audit Workflow
sequenceDiagram
participant Dev as Developer
participant Claude as Claude Code
participant Files as Codebase
Dev->>Claude: security-audit src/api/checkout.ts
Claude->>Files: Read checkout.ts
Claude->>Files: Trace imports - read auth middleware
Claude->>Files: Trace imports - read cart service
Claude->>Files: Read payment processor integration
Claude-->>Dev: 3 findings: 1 high, 2 medium
Dev->>Dev: Review each finding
Dev->>Claude: Fix the high severity finding in checkout.ts
Claude->>Files: Edit checkout.ts
Claude-->>Dev: Fix applied - here is what changed and why
Dev->>Dev: Review diff, approve change
The human-in-the-loop is deliberate. Claude reports findings and explains them but does not automatically patch them. Security decisions should stay human-controlled — an automated fix to a security issue can introduce a different vulnerability if the surrounding context is not fully understood.
What Claude Catches vs What It Misses
| Category | Claude | Semgrep / ESLint |
|---|---|---|
| SQL injection (parameterised) | Good | Good |
| Business logic flaws | Excellent | Poor |
| IDOR | Good | Poor |
| Multi-step exploits | Good | Very poor |
| Known CVE patterns | Limited | Excellent |
| Supply chain issues | Poor | Good (with plugins) |
| Performance | No | No |
The right approach is both. Run your standard linters in CI for fast, deterministic coverage of known patterns. Use Claude Code for deeper audits before major releases, after significant changes to auth or payment flows, or when onboarding to an unfamiliar codebase.
Practical Tips
Be specific about what to audit. “Audit the whole repo” produces shallow results across everything. “Audit the checkout flow” produces deep results where it matters.
Provide business context. The more Claude understands about what your application is supposed to do, the better it can identify where it does something unintended. Include a brief description of the feature you are auditing.
Iterate on findings. Ask Claude to explain its reasoning. “Why is this IDOR exploitable specifically?” often reveals whether it is a real finding or a false positive, faster than manually tracing the code yourself.
Run audits on a clean context. Start a fresh session for security audits. Stale context from unrelated work can reduce the quality of analysis.
Integration with CI
For teams wanting automated security feedback on pull requests, Claude can run as part of a GitHub Actions workflow:
name: Security Review
on: [pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Claude Security Audit
run: |
changed=$(git diff --name-only origin/main...HEAD | grep -E '\.(ts|js|py|go)$')
if [ -n "$changed" ]; then
echo "$changed" | xargs -I{} claude -p \
"Security audit of {}: check for auth gaps, injection risks, and business logic flaws. Report findings with severity." \
--output-format json
fi
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
This runs a targeted audit on only the files changed in the PR — keeping it fast and focused.
