DevPik Logo
claude code skillssecurity auditai securityagent skillsopen source

Cloudflare's Security Audit Skill: An AI Auditor Built to Disprove Itself

A coding-agent skill that turns Claude Code into a security auditor, where the agent that checks a finding is never the agent that found it. How the six phases work, what the three verdicts mean, and the sandbox requirement most people will skip.

ByMuhammad Tayyab12 min read
All open source picks
cloudflare/security-audit-skill
The official repository — this write-up is not affiliated with the project.
5.5kJavaScriptMIT

What It Is

Cloudflare has open-sourced the security audit skill that seeded its internal vulnerability discovery harness. It is MIT licensed, it passed 5,500 GitHub stars within three months of the repository being created, and it installs with one command.

It is not a scanner. It is a skill, a folder of structured instructions that a coding agent loads and follows. You point Claude Code, Codex, Cursor or another agent at a codebase, ask for a security audit, and the skill orchestrates a fleet of isolated sub-agents through six phases, producing machine-readable findings that another agent has already tried and failed to disprove.

The interesting part is not that an AI looks for bugs. Plenty of tools do that, and most of them drown you in false positives. The interesting part is the architecture built specifically to stop that happening, which is what the rest of this covers.

This Is Not Anthropic's Claude Code Security

Worth clearing up first, because three similarly named things are circulating and they are easy to confuse.

  • Claude Code Security is Anthropic's own product, announced February 2026. It is a hosted feature with a findings dashboard and suggested patches, built into Claude Code itself.
  • anthropics/claude-code-security-review is a GitHub Action from Anthropic that reviews pull request diffs for vulnerabilities in CI.
  • cloudflare/security-audit-skill is this: a third-party, MIT-licensed skill you install yourself, which audits a whole repository rather than a diff and writes verified artifacts to disk.

They are not competitors so much as different shapes. Anthropic's action reviews what changed. This audits what exists, across the whole codebase, and keeps a ledger so the next run can target what the last one missed.

If you searched for one and landed on the other, that is why.

The Six Phases

The audit is a pipeline, and each stage hands structured state to the next rather than passing prose around.

  1. Reconnaissance. Map the architecture, trust boundaries, input surfaces and any prior evidence. Writes architecture.md and coverage-ledger.json, a deterministic record of what exists and therefore what must be examined.
  2. Coverage-led hunting. Assign isolated hunters to units drawn from the ledger, record every check each one performs, then run coverage critics whose only job is to find the gaps the hunters left.
  3. Candidate validation. Hand every unique candidate to a fresh verifier whose instruction is to disprove it.
  4. Structured output. Write confirmed, needs_validation and rejected records to findings.json, then validate that file against report-schema.json.
  5. Independent record verification. New agents re-check the final source claims. Any material replacement gets another independent verifier on top.
  6. Target-neutral reporting. Derive REPORT.md, FINDINGS-DETAIL.md and NEEDS-VALIDATION.md from the verified records.

Two zero-dependency Node validators enforce the structure rather than trusting the model to hold the format: validate-coverage-ledger.cjs runs after the ledger is created and after every later update, and validate-findings.cjs runs in phase 4 and again after every phase 5 replacement.

That detail matters more than it looks. The schema is not documentation, it is a gate. A finding that does not conform does not get written.

The Idea That Makes It Work

One line in the design principles carries most of the weight:

Adversarial validation. The agent that checks a finding is never the agent that found it.

Anyone who has asked a language model to review its own output knows why. A model that has just argued a piece of code is vulnerable is heavily primed to keep agreeing with itself. Ask it to check, and it checks in a way that confirms. The result is a confident report full of things that are not real.

The skill removes the option. The verifier is a separate agent, spawned fresh, with no memory of the hunt that produced the candidate, and its instruction is not "confirm this" but "disprove this". A finding survives only by resisting a genuine attempt to kill it.

The other principles work in the same direction, and all of them reduce output rather than increase it:

  • Only confirm established boundary failures. A source-grounded lead that could not be carried through stays as needs_validation with its exact unresolved fact recorded. It does not get promoted on vibes.
  • Severity requires impact. Likelihood multiplied by impact, not distance from a checklist.
  • Defense-in-depth gaps are not vulnerabilities. If layer A already stops the attack, the absence of layer B is a hardening note, not a finding.

That last one quietly eliminates the majority of what automated tooling normally reports.

Three Verdicts, and Why the Middle One Matters

Most scanners give you a finding or silence. This gives you three states, and the middle one is the most useful of the set.

VerdictWhat it means
confirmedA complete source trace and a bounded observed result. Something was actually established.
needs_validationA real, source-grounded lead with one exact unresolved fact. Carries no severity.
rejectedA candidate that a verifier successfully disproved, kept on the record.

needs_validation is where an honest system puts the work it could not finish. A scanner that only emits confirmed or nothing has to make a silent judgement call on every borderline lead, and you never see the ones it dropped. Here the lead is written down, with the specific fact that would resolve it, so a human can spend ten minutes on the thing the agent could not reach rather than re-deriving the whole analysis.

Keeping rejected records is the other half. It means a later run does not spend budget re-investigating a candidate that was already killed, and you can audit the auditor by reading what it threw away and why.

The Coverage Ledger and Repeat Runs

The coverage-ledger.json file is what separates this from a one-shot prompt.

Hunters are assigned from ledger units rather than wandering the codebase, every check they run is recorded, and coverage critics then read the ledger looking for what was never examined. Coverage becomes a tracked quantity instead of a hope.

Because the ledger persists, runs are additive. A second audit reads the previous ledger and findings, targets the gaps, revalidates source that has changed since, and carries forward evidence that still holds. Crucially it does not treat stale or unresolved work as covered, which is the obvious way this kind of thing goes wrong.

Cloudflare's own measured result is the most quotable number in the repository:

In our test runs, a single run found roughly half of the vulnerabilities that repeated runs found in total.

Read that as a warning rather than a feature. If you run this once, see a clean report and conclude the code is fine, you are drawing a conclusion the tool's own authors say is not supported. One run is roughly half an audit.

If you are running repeat audits, a JSON diff between two findings.json files is the fastest way to see what the latest pass actually added, and the schema generator is useful if you want to build your own tooling on top of the report-schema.json contract.

The Attack Class Library

The repository is mostly prompts, and the prompts are organised by target type. Eleven files carry hunting classes, so the agent loads what is relevant to what you are auditing rather than sweeping everything with the same generic checklist.

TargetFile
Core and wildcard classesATTACK-CLASSES.md
Native, memory safety, kernelMEMORY-SAFETY-AND-BINARY.md
Prompt injection, agents, tool useAI-AND-LLM.md
HTTP framing, cache, auth protocolsWEB-PROTOCOL-AND-AUTH.md
DOM injection, prototype pollution, UI redressCLIENT-SIDE.md
Dependencies, CI, release, signingSUPPLY-CHAIN-AND-RELEASE.md
IAM, IaC, containers, serverlessCLOUD-AND-DEPLOYMENT.md
RPC, serialization, queues, webhooksPROTOCOLS-RPC-AND-MESSAGING.md
Quotas, workers, operator spendRESOURCE-EXHAUSTION-AND-AVAILABILITY.md
Tenant isolation, backup, deletion, restoreDATA-ISOLATION-AND-LIFECYCLE.md
Deep links, webviews, local IPCDESKTOP-MOBILE-AND-LOCAL-IPC.md

The presence of AI-AND-LLM.md is worth noting on its own. If you are shipping anything agentic, prompt injection and tool-use abuse are now part of your attack surface, and this is one of the few open checklists that treats them as first-class rather than a footnote.

RESOURCE-EXHAUSTION-AND-AVAILABILITY.md covering "operator spend" is a very Cloudflare detail. Someone running up your cloud bill is a real attack, and almost nothing else checks for it.

Installing and Running It

Installation goes through the skills.sh package manager, which is the emerging standard for agent skills:

bash
npx skills add https://github.com/cloudflare/security-audit-skill \
  --skill security-audit

Add --global for a user-level install rather than per-project. Then start your agent in the codebase and ask in plain language:

security audit this codebase
find security vulnerabilities in ./src
do a security review, output to ~/audits/my-project

The skill activates on matching intent. A direct audit request runs the full pipeline; security questions and narrower vulnerability work run in guidance mode unless you explicitly ask for report artifacts.

One behaviour worth knowing before you start: in full audit mode, an unspecified output directory defaults to ~/security-audit-skill/<repo-name>/run-<N>, outside your repository. It writes inside the repo only when you explicitly choose a directory that version control ignores. That is a deliberate and sensible default, since audit artifacts name your unfixed vulnerabilities in detail and committing them by accident would be genuinely bad. If you do want them in-tree, sort your .gitignore first.

The Sandbox Requirement People Will Skip

The requirements list has three entries, and the third is the one that will get ignored.

  • A coding agent whose model supports tool use and parallel sub-agents.
  • Node.js, for the two zero-dependency validators.
  • An OS-enforced sandbox for anything that executes target-controlled code: builds, tests, processes, browsers, emulators, fuzzers and fixtures.

The sandbox specification is precise. External networking disabled, a sanitized allowlisted environment, enforced resource limits, and writes permitted only to assigned scratch paths.

Think about what is being asked here. To verify a vulnerability properly you often have to run the suspect code. That code is, by hypothesis, possibly malicious, and you are handing it to an autonomous agent with tool access on your machine. Without isolation, an audit of a hostile repository is an excellent way to compromise yourself.

The skill handles the absence well rather than pretending: without those controls it declines to execute target code and leaves the lead as needs_validation instead. You get a more conservative audit rather than a dangerous one. That is the right failure mode, but it does mean an unsandboxed run will quietly produce fewer confirmed findings, and you should know that is why rather than concluding the code is clean.

Where It Came From, and What It Is Not

This skill seeded the harness described in Cloudflare's Build your own vulnerability harness post. That harness grew into a multi-stage, fleet-wide system. What has been released is the single-repo starting point it evolved from, not the full internal machine.

So calibrate accordingly. This is a serious, well-structured methodology from a team that runs it in anger, and it is genuinely more rigorous than most of what gets called AI security tooling. It is still not a penetration test, not a compliance artifact, and not a replacement for someone who knows your threat model.

What it is good for: a thorough, structured, repeatable first pass that tells you plainly what it established, what it could not resolve, and what it ruled out. For an open-source maintainer with no security budget, or a team auditing a dependency before adopting it, that is a substantial thing to get for free under MIT.

Two costs to plan for. It spawns many sub-agents, so a full audit consumes real token budget. And the honest reading of "one run is half an audit" is that you should expect to run it more than once on anything that matters.

Frequently Asked Questions

Is this the same as Anthropic's Claude Code Security?

No. Claude Code Security is Anthropic's own hosted feature with a findings dashboard, and anthropics/claude-code-security-review is their GitHub Action that reviews pull request diffs. This is a third-party, MIT-licensed skill from Cloudflare that you install yourself. It audits an entire repository rather than a diff, and it writes a coverage ledger and verified findings to disk so later runs can target what earlier ones missed.

How do I install the security audit skill?

Run npx skills add https://github.com/cloudflare/security-audit-skill --skill security-audit, adding --global for a user-level install rather than per-project. Then start your coding agent in the target codebase and ask it in plain language, for example "security audit this codebase". The skill activates automatically when the request matches its trigger.

Does it work with agents other than Claude Code?

Yes. The requirement is a coding agent whose model supports tool use and parallel sub-agents, not a specific vendor. It installs through skills.sh, the agent-skill package manager, which supports Claude Code, Codex, Cursor and other compatible agents. Parallel sub-agents are the hard requirement, because the isolated hunters and independent verifiers are the whole design.

What do confirmed, needs_validation and rejected mean?

confirmed means a complete source trace and a bounded observed result, so something was actually established. needs_validation is a real source-grounded lead with one exact unresolved fact, and it deliberately carries no severity. rejected is a candidate that a verifier successfully disproved, kept on the record so later runs do not re-investigate it. Every record is validated against report-schema.json by a zero-dependency Node validator.

Why does it avoid false positives better than a normal scanner?

Because the agent that checks a finding is never the agent that found it. A fresh verifier with no memory of the hunt is instructed to disprove the candidate rather than confirm it, so a finding survives only by resisting a real attempt to kill it. Three further rules cut output: only established boundary failures are confirmed, severity requires likelihood multiplied by impact rather than checklist deviation, and defense-in-depth gaps are recorded as hardening notes instead of vulnerabilities.

Do I really need a sandbox?

You need one for any finding that requires executing target-controlled code, which includes builds, tests, browsers, emulators and fuzzers. The spec is an OS-enforced sandbox with external networking disabled, a sanitized allowlisted environment, enforced resource limits and writes only to assigned scratch paths. Without it the skill refuses to execute target code and leaves the lead as needs_validation, so an unsandboxed run is safe but produces fewer confirmed findings.

Is one audit run enough?

No, and Cloudflare says so directly: in their test runs a single run found roughly half of the vulnerabilities that repeated runs found in total. Runs are additive by design, since the coverage ledger and prior findings let a later pass target gaps, revalidate changed source and carry forward evidence that still holds without treating unresolved work as covered. Treat a single clean report as half an audit.

Where does it write its output?

In full audit mode with no directory specified, it defaults to ~/security-audit-skill/<repo-name>/run-<N>, outside your repository. It writes inside the repo only when you explicitly choose a path that version control ignores. That default is deliberate, because the artifacts describe your unfixed vulnerabilities in detail and accidentally committing them would expose exactly what an attacker wants.

Related DevPik tools

Muhammad Tayyab

Written by

Muhammad Tayyab

CEO & Founder at Mergemain

Muhammad Tayyab builds free, privacy-first developer tools at DevPik. He writes about AI trends, developer tools, and web technologies.

More open source picks