Independent AI intelligence Two editions daily · ET
Fervor AI

Analysis · September 19, 2026 · repo

security-audit-skillCloudflareai-skillsagent-securitymulti-agentagent-harness

Cloudflare's security-audit-skill Will Refuse to Start Rather Than Run a Thin Audit

The transferable part of Cloudflare's open-source agent skill is not the attack classes. It is a budget gate, a coverage ledger, and a set of rules that make "we did not look there" a first-class output.

Most agent skills are a prompt with good taste. Cloudflare's security-audit-skill, which went up the Trendshift daily board this week at roughly sixteen thousand stars, is a folder of markdown files and two zero-dependency Node validators under MIT. No model, no service, no binary, no releases at all. And buried in its SKILL.md is a rule I have not seen in any other published agent workflow:

If the budget you gave it cannot fund reconnaissance plus the reserved critic and verifier calls, it launches no agent. Not a smaller audit. Not a best-effort pass with a disclaimer at the top. Zero agents, a run_status of incomplete, and a machine-readable reason string: budget_cannot_fund_reconnaissance_and_reserves.

That is a strange thing to build. It is also, I think, the most reusable idea in the repository, and it has nothing to do with security.

The thing everyone will copy, and the thing worth copying

The obvious value in this repo is the attack-class library: eleven companion files covering memory safety, prompt injection, HTTP request framing, DOM injection, supply chain, IAM and container configuration, RPC and queue protocols, resource exhaustion and operator spend, tenant isolation and deletion lifecycle, local IPC and deep links. That is a serious body of security knowledge in a form an agent can load on demand, and plenty of people will fork it for the checklists alone.

They will be taking the least interesting part.

The SKILL.md that orchestrates those companions is a document about how to stop an agent from lying to you about coverage. Cloudflare wrote it for security audits because that is where a confident, incomplete answer does the most damage. The structure generalizes to any task where an agent searches a large space and then tells you what it found: code review, dependency triage, log investigation, compliance mapping, refactor planning. Anywhere the failure mode is a partial answer wearing a complete one's clothes.

It is guidance until you say otherwise

The skill opens by refusing to activate itself: "This skill is guidance by default. Loading it does not authorize the complete audit workflow or file creation."

Guidance mode answers security questions and does focused reviews without creating an output directory or writing artifacts. Full audit mode runs all six phases. And if a request could plausibly mean either, the skill is instructed to ask one focused question before creating files.

Most skills treat being loaded as being invoked. Separating the two is the difference between a tool you can keep installed and one you have to keep uninstalling.

No agent verifies its own finding

The README compresses the design into one sentence: "The agent that checks a finding is never the agent that found it."

Mechanically: Phase 2 hunters work isolated units from a coverage ledger and emit structured candidates. Phase 3 hands every deduplicated candidate to a fresh verifier whose job is to disprove it. Phase 5 uses another set of fresh agents to verify the final source claims, and a material replacement at that stage gets yet another independent verifier.

The write isolation enforcing it is more paranoid than the prose suggests. The parent agent is the only writer of the shared run files. Every hunter and verifier gets a unique root with its own scratch/ and artifacts/, and agents may not touch shared files, target source, retained artifacts, or another agent's directory. Agent IDs are lowercased to prevent case-fold collisions and forbidden from matching Windows device names like con, aux or lpt1, which is the kind of detail you only write after something went wrong once.

Moving a file out of an agent's scratch into retained artifacts is an eleven-step procedure: retained non-inheritable directory descriptors, no-follow directory-relative walks, fstat checks for regular-file type and link count exactly one, byte limits enforced twice, a re-fstat after the copy to reject a changed identity or size. Symlinks, FIFOs, sockets, devices, hard-linked files and archives are all refused. If any check cannot be enforced, the entry is discarded, and if it was decisive evidence the finding stays needs_validation with the exact promotion blocker recorded.

That is not security theater about the target. That is treating your own sub-agents' output directories as untrusted input, which is the correct posture and almost nobody adopts it.

The ledger exists to record what you did not look at

Every other part of this workflow serves one file. coverage-ledger.json holds deterministic units of the audit surface, seeded before hunting starts and updated by the parent alone after every agent result.

The rules around it make false completeness structurally hard. "No one pass is complete." A scoped run seeds units only for in-scope surfaces and records everything else as out_of_scope, "never as covered." On re-runs, "A prior source ref alone is not evidence that a path is unchanged," and a prior confirmed finding carries forward only if the relevant source is unchanged and it passes the current verification path anyway. A prior quick or scoped ledger "contributes only its recorded evidence and gaps, never an implied 'rest is fine.'" And when there is no prior ledger at all: "say so in the final coverage statement. Never imply that one run exhausts the target."

The three run profiles, quick, standard and deep, come with the constraint that keeps them honest: "Profiles change breadth and redundancy, never the evidence bar." A cheaper run covers less. It does not lower the standard for calling something confirmed.

The budget gate, which is the actual invention

Agent budgets usually work one way: spend until you hit the cap, then stop wherever you are. Which means the work that gets cut is whatever came last, and what comes last is verification.

Cloudflare inverted it. The budget is a maximum number of agent invocations across all phases, spent in a fixed order with the checks reserved before the hunting. Reconnaissance and every critic count as invocations. Standard and deep runs reserve one post-wave critic plus one distinct final-clean critic before every hunter wave, plus verifier cost from the profile, defaulting to 30% of the remaining balance when the candidate count is unclear, and the rule attached is absolute: "Never assign hunters into either reserve." Hunters get what is left, in priority order. Before a later wave its critic is reserved again, and if the remainder cannot cover that plus validation, the wave launches no hunters at all and its units go to deferred with reason budget_cannot_reserve_critics_and_validation.

And the hard floor at the top: apply the gate before launching any reconnaissance agent, and if the requested budget cannot fund the minimum, launch nothing and ask for a larger budget, a narrower scope, or a different profile. If the request comes back unchanged, record the run as incomplete and report that no audit pass ran.

There is a matching rule for the other end. If the budget runs out mid-validation, stop hunting, validate candidates in fingerprint order while it lasts, and set validation_budget_exhausted. Then, explicitly: do not put an unvalidated candidate in findings.json, do not relabel it needs_validation, and do not report the run as complete.

The sentence that captures the whole philosophy sits in the pre-wave check. If the budget clearly cannot cover the plan, say so and propose a tighter scope or a coarser profile "instead of silently thinning evidence."

Three more rules worth stealing

Fail closed on the sandbox. Running target-controlled code requires an OS-enforced sandbox: no external network, an allowlisted empty environment, a read-only target, explicit CPU, memory, process, file-size and wall-clock limits. If every control cannot be enforced, the skill does not execute target code. It reports the missing capability as a needs-validation blocker and supplies a safe validation plan instead. The default is refusal, not degradation.

Uncertainty gets no severity. needs_validation means a specific source-grounded hypothesis is blocked, and the skill states plainly that it is "not a low-confidence confirmed vulnerability." Only confirmed records get severity, and severity "cannot exceed demonstrated impact." The high-versus-medium discriminator is a question you can ask about any finding in any domain: "If you cannot state the concrete damage, the severity is lower than it feels."

Two terminal states, no third. A run ends with all Phase 6 artifacts written and both validators passing, or with run_status: "incomplete", its exact reason, and the gap disclosed in the report. "Never stop mid-phase." There is no way for the workflow to trail off without saying so.

Put this into practice

Install it per project, not globally. npx skills add https://github.com/cloudflare/security-audit-skill --skill security-audit. The --global flag exists, but a skill this large costs context in every session you open, and you do not want an audit workflow resident while you are writing CSS.

Start in guidance mode. Ask a security question about a subsystem you already understand and watch how it reasons. That tells you whether your model handles the delegation structure before you spend a full audit's worth of calls finding out it does not.

Set an explicit budget on your first full run, and set it slightly too low. Watching the gate refuse to launch is the fastest way to internalize what it is protecting. Then raise it.

Read NEEDS-VALIDATION.md before REPORT.md. The confirmed findings are what the run proved. The needs-validation file is what it could not reach, each entry carrying its exact unresolved fact. On a first run against a real codebase, the second file is usually the more informative document, and it is the one that tells you what to fix about your sandbox.

Run it twice and diff. Cloudflare published the number that makes this necessary: "In our test runs, a single run found roughly half of the vulnerabilities that repeated runs found in total." A vendor telling you its own tool's single-shot recall is about 50% is unusual, and it converts directly into an operating instruction.

Take the shape into your own work. Pick any agent workflow you own that searches and reports. Add three things: a ledger of what was in scope, with never-looked-at as a distinct state from looked-and-found-nothing; a fresh agent that tries to disprove each finding, with no access to the finder's reasoning; and a reserve carved out of your budget for that verification before any exploration is funded. None of that is security-specific, and all of it is the part that makes the output trustworthy.

What I am not claiming

I have not run this skill. Everything above is a reading of the published README.md and SKILL.md on main, fetched with a cache-buster on September 19, 2026. That distinction matters more here than usual.

A skill is prose addressed to a model. The SKILL.md describes what the workflow is supposed to do; it does not make the model do it. An agent can read "never assign hunters into either reserve" and assign hunters into the reserve, and nothing in the markdown stops it. The two validators, validate-findings.cjs and validate-coverage-ledger.cjs, are the only parts that execute, and they check structure: schema conformance of findings.json, internal consistency of the coverage claim. They cannot check whether a hunter actually hunted, whether a verifier genuinely tried to disprove, or whether the budget accounting was honest. The refusal machinery I have spent this article praising is, in the end, instructions that a sufficiently sloppy or sufficiently agreeable model can ignore. That is the gap, and it is the gap in every skill ever shipped.

The "roughly half" figure is Cloudflare's own, from its own test runs, with no sample size, no target list, and no method published. It is an honest disclosure and it is not a measured recall rate you can carry to another codebase.

The sandbox requirement is the real adoption barrier and I want to be blunt about it. No external network, allowlisted empty environment, read-only target and toolchain, scratch-only writes, explicit resource limits. Most developers pointing an agent at a repo this weekend will not have that, which means the workflow will correctly refuse to execute target code and most of their findings will land in NEEDS-VALIDATION.md. That is the system working as designed, and it will feel like the tool not working.

I also did not evaluate the attack classes themselves. Whether the prompts in WEB-PROTOCOL-AND-AUTH.md actually find request-framing bugs is an empirical question I have no data on, and this article deliberately does not claim they do.

The part that transfers

Strip the security domain out of this repo and what remains is a claim about how an agent should behave when it cannot do the whole job: say so, in a specific place, in a form that a later run can pick up, and refuse the work rather than produce a thin version of it.

That is a hard thing to build because it is a hard thing to want. Every incentive pushes the other way. A tool that returns findings feels useful; a tool that returns "I could not fund verification, give me a bigger budget or a smaller scope" feels broken. Cloudflare built the second one on purpose and published the recall number that explains why.

Open your own agent's last report. Find the place where it told you what it found. Then look for the place where it told you what it never looked at. If that second place does not exist, you now know what to build next.

Sources: cloudflare/security-audit-skill README, SKILL.md on main, Build your own vulnerability harness, Skills CLI.


Medium metadata

Title: Cloudflare's security-audit-skill Will Refuse to Start Rather Than Run a Thin Audit Subtitle: The transferable part of Cloudflare's open-source agent skill is not the attack classes. It is a budget gate, a coverage ledger, and a set of rules that make "we did not look there" a first-class output. Tags: AI Agents, Security, Open Source, Software Engineering, Claude Code