Cloudflare's audit skill has a second agent rebut each bug
A teardown of Cloudflare's open-source security-audit skill: what recon, ledger, hunters, verifiers, scripts and sandbox each receive and leave behind.
The core of the security-audit skill that Cloudflare published on GitHub under the MIT license is not how many agents it launches. It is a single rule: “the side that finds a bug does not get to grade its own result.” Recon, ledger, hunters, critic, verifiers, validation scripts, sandbox and budget are all devices that keep this rule from breaking, and the rule is what gives the word “confirmed” its weight in a report. As of Oct 27, 2026 (UTC), the repository has 48.2k stars, about 3,000 forks and 14 commits, and the last commit is from Sept 14. This article opens the repository’s files from the outside in and follows what each part receives and what it leaves behind.
Twenty files get installed, and only four are code
Installation goes through the Skills CLI from skills.sh. Add --global to install for the whole user account; the option for choosing an agent is listed in npx skills --help.
npx skills add https://github.com/cloudflare/security-audit-skill \
--skill security-audit
The skill folder (skills/security-audit/) contains 20 files. Fifteen are markdown that the agent reads, one is the result-format JSON, and the only code that runs is two validation scripts and their two test files.
skills/security-audit/
├── SKILL.md entry point: modes, safety rules, profiles and budget, principles
├── RECONNAISSANCE.md phase 1 instructions (recon, building the ledger)
├── HUNTING.md phase 2 instructions (assigning hunters, the critic)
├── VALIDATION-AND-REPORTING.md phases 3-6 instructions (validation, output, re-check, report)
├── ATTACK-CLASSES.md 9 base attack classes, rules for picking companion documents
├── (10 companion documents) memory safety and binaries, AI and LLM, web protocols and auth,
│ clients, supply chain and releases, cloud and deployment,
│ RPC and messaging, resource exhaustion, data isolation,
│ desktop and mobile
├── report-schema.json format of result records
├── validate-findings.cjs + test file
└── validate-coverage-ledger.cjs + test file
There are two requirements: a coding agent backed by a model that supports tool calls and parallel sub-agents, and Node.js to run the validation scripts. The first run goes like this.
- Commit or clean up the repository you want audited, then start the agent in that folder. The skill writes the commit it reviewed and whether the working tree was clean into
run-metadata.json. - Ask the way the README's examples do:
security audit this codebase,find security vulnerabilities in ./src, ordo a security review, output to ~/audits/my-project. - If the request is ambiguous, the agent asks exactly one question before creating any file: whether you want a full audit that produces report files, or only a look at the part you are curious about.
- When it finishes, start with the first section of
REPORT.mdin the output folder: scope, profile, whether the check was partial, and budget.
There are two modes. The default “guidance mode” uses only what is needed and creates no files; “full audit mode” runs all six phases only when you ask for an audit or penetration test, a comprehensive review, or report files. If you do not specify an output folder, results go to ~/security-audit-skill/<repository name>/run-<number>, and inside the target repository only if you pick a folder that version control ignores completely. One run produces this layout.
~/security-audit-skill/my-project/run-1/
├── run-metadata.json profile, scope, budget, reviewed commit, run status
├── architecture.md recon result (about 1,000 words)
├── coverage-ledger.json status and check records for every cell
├── findings.json confirmed / needs validation / rejected records
├── REPORT.md scope, summary, confirmed table, needs-validation table, hardening advice, ledger summary
├── FINDINGS-DETAIL.md paths and fixes for confirmed medium-and-above findings
├── NEEDS-VALIDATION.md why unresolved items are blocked, and the plan to check them
└── agents/<id>/ scratch/ and artifacts/ for each agent
Six phases, and where fresh agents take over
The README splits the audit into six phases: recon, ledger-driven hunting, candidate validation, structured output, record re-validation and reporting. The figure below puts, for each phase, who does the work and which file it leaves behind on one page. Orange marks newly spawned agents; the dark boxes are work done by the parent (the agent that runs the whole audit) or by scripts.
Figure 1. Phases where agents work (orange) alternate with phases handled by the parent and scripts (dark)
What to notice in the figure is who writes the files. Only the parent can edit the ledger and findings.json, and a hunter cannot write outside its own scratch folder (scratch/). An agent only hands back its result as a single JSON object; reflecting it in the ledger and running it through the validation script is the parent’s job. Because the side that holds state and the side that does the work are separate, one agent’s bad judgment cannot contaminate the whole ledger.
The original skill described in Cloudflare’s blog (Build your own vulnerability harness, June 18, 2026) differs a little from today’s public version. When it started as a skill of about 450 lines, it had three recon agents and seven phases, and the seventh sent surviving results to an internal collection API. The public version drops that last step, which depended on internal systems, and ends at the report after six phases; recon is split into four agents, one of which handles “how far can this be run locally.”
One limit is also visible straight from the structure. The skill is markdown instructions, so whether the rule “spawn a new agent” is actually followed depends on the host agent that runs the skill. A comparison of open-source AI security harnesses that Semgrep published in July 2026 classifies this skill as a “methodology that costs only the host’s tokens” in the same spirit. Intelligence and isolation come from the host, and what the skill supplies is the procedure and the record format. The separate scripts that check the format of the ledger and result files by code read as an attempt to close that gap.
Four recon agents draw a 1,000-word map
Recon is handled in parallel by four read-only research agents. They read the target, look at the local build and configuration state, and return structured facts to the parent. They do not connect to deployed endpoints, external auth services, registries or cloud APIs, they write no files, and they run no builds or tests in this phase.
| Agent | Question it owns | What it returns |
|---|---|---|
| 1a Product, stack, local operation | What does this software do? | Product type and users, languages and frameworks, entry points and subsystem boundaries, offline build and test commands (listed, not run), inputs the target controls, missing toolchains |
| 1b Principals, privileges, controls | Who can do what? | Low-trust principals and the actions designed for them, authentication at each entry point, per-resource authorization and tenant scope, privilege change, revocation and recovery paths, controls that rely on the deployment environment |
| 1c Entry surfaces, copies, sinks | Where does input flow? | Every input entry point visible in the source (HTTP, RPC, files, command line and config, plugins, cloud events, model tool arguments, deep links, local IPC), transformations, copies and sinks, limits, parallel paths |
| 1d Local execution, deployment visibility | How far can it be run? | Offline tests and fixtures, processes that can run on an isolated loopback, commands to forbid (dependency downloads, publishing, paid APIs), controls that are decisive but live outside the repository, whether the platform can enforce a sandbox |
If the deployment style or a subsystem is clearly different, the parent can attach more dedicated recon. If the budget blocks it, that area gets no agent, is planted as a deferred cell, and is named as a gap in the report.
The four results are merged into architecture.md, capped at about 1,000 words. It has eight items: the product, principals and what is protected; a baseline from comparable software (omitted when there is no sensible comparison); the technology stack and the limits of the offline build; the entry surfaces and the main paths from source to sink; the strongest control visible in the source at each boundary; the repository-based starting paths; the previous run’s gaps and re-validation targets; and a summary of companion-document selection. The baseline item carries a caveat: it is for calibration and is not grounds to dismiss a proven vulnerability. This document goes to every hunter in full, so if it falls short, every hunter misses the same places.
How one ledger cell becomes one hunter’s assignment
When recon ends, the parent builds the ledger (coverage-ledger.json). One cell (unit) is entry surface × trust boundary × subsystem × attack class, and for deep checks a lifecycle (state changes such as create, update, delete) is added. A cell’s identifier is not a label. It is stable references taken from the source, normalized to Unicode NFC, percent-encoded and joined with ::. Wave number, agent, verdict, severity and line numbers never enter the identifier, so the same cell keeps the same name in the next run. If two cells have the same name but different contents, they are rejected as a conflict instead of being merged.
Every cell carries a status.
| Status | Meaning |
|---|---|
planned · in_progress |
Not yet assigned; a hunter is working on it |
covered |
The path followed and the checks are non-empty, and no unresolved fact remains |
candidate |
A candidate came out. It is the verifier’s turn |
blocked |
The hunter cannot go further by source or local means |
deferred |
Postponed because of budget or profile. It may be unassigned |
out_of_scope · not_applicable |
Outside the scope (kept for a later full run), or does not apply |
The order in which cells are handed to hunters is fixed. When the agent count hits its limit, cells are assigned from the top of the list below, ties are split by identifier order, and the reason is written into the ledger.
- Entry surfaces with no authentication, or the lowest trust
- Boundaries that guard high-value resources such as credentials, other tenants’ data, code execution and release authority
- Places left empty in the previous run, re-validation targets, and places where the source changed
- Cell kinds that often produced confirmed results for this type of target
The instruction given to a hunter is nine parts in a fixed order: a two-sentence role introduction, the full architecture.md, the IDs and starting paths of the assigned cells, the verbatim text of the selected attack-class blocks, the blocks deliberately left out and why, the hunting method and the procedure for promoting a candidate, the validation rules, the list of items already confirmed from the same source plus the cells other hunters hold, and finally its own scratch folder path and the result schema. What marks this skill is that attack classes are not mentioned by name only; the original blocks are inserted as they are. There are nine base classes (injection, access control, resource and file handling, crypto and secrets, business logic, feature abuse and leakage, chaining and trust boundaries, wildcard, and the obvious), and the ten companion documents are attached only when recon actually found the trust boundary that document covers. They are never picked because a language or a dependency name looks similar. The AI and LLM companion document, for example, applies to code where a model takes part in a trust-bearing decision, such as retrieval-augmented generation, agent memory, tool-calling loops and MCP servers. It carries a caveat that prompt injection alone is not a vulnerability: there has to be a code-level boundary failure, where a deterministic permission check is missing or bypassed.
When a hunter finishes, it returns one JSON object. The skill forbids prose reports because prose cannot be deduplicated or validated. The skeleton looks like this.
{
"units": [ per cell: disposition (covered | candidate | blocked), the path followed, checks made (method is source or local) ],
"candidates": [ candidates in the schema's shape. The verdict field is proposed_verdict ],
"hardening": [ hardening notes that are not vulnerabilities ],
"uncovered": [ places not examined, and why ]
}
When a hunter wave (one round of parallel exploration) ends, the critic (coverage critic) follows immediately. It is a newly spawned read-only agent that reads the source but does not write or run the target. It looks for unconnected entry points, sibling paths, missing lifecycles, companion documents without a partner, exclusions without a reason, and cells closed without a path or a check, and returns new cell candidates and cells to reassign. What the critic produces is not a finding but an assignment saying “look here too.” A reassigned cell goes to a new agent that starts empty-handed; the earlier evidence is kept in attempts and not copied, so the earlier hunter’s conclusion cannot pull the next one along. Waves repeat while the critic keeps producing new work and while planned cells remain. In standard and deep, the run ends only when a separately reserved critic checks once more at the end and points out nothing.
The bar for getting on the candidate list
For a hunter to file a candidate, the facts visible in the source must form one unbroken line: who (a low-trust principal), with what (an input or action), what control it had to pass, how that control broke and which boundary was crossed, whose what is affected as a result, and what following the source or running locally showed. The candidate rules are strict in other ways too. They forbid inflating one crash into code execution, ordinary work into a shared-availability problem, or a same-principal action into privilege escalation, and facts not visible in the source go out as needs_validation with the exact reason they are blocked. If nothing remains, the hunter returns an empty candidate array.
What becomes a candidate
- A source path that starts at a low-trust principal and gets past the intended control, together with the strongest defense on that path
- A root cause that can be identified by a fingerprint taken from the source
- A case that became
needs_validationbecause exactly one fact outside the repository, such as a deployment setting, remains - A claim lowered to match the proven impact
What is filtered out here
- Pointing out that a best practice is missing, or a missing defense layer that would be closed by one more blocking layer (recorded only as a hardening recommendation)
- Speculation about provider, proxy, browser or deployment behavior
- Self-impact inside the same privilege, or the exercise of an intended privilege
- A parser or runtime effect written more strongly than what was actually observed
- Re-reporting an item already confirmed from the same source
A fingerprint is a value taken from the source that excludes line numbers, wave, agent, severity and verdict. Even when several hunters describe the same root cause in different words, they merge into one candidate, and it is the key by which the next run recognizes yesterday’s confirmed items, which is why it sits at the center of the design.
What the rebutting agent receives and hands back
Candidates, once duplicates are merged, go to a new agent (general) that did not create them. The input this verifier receives is deliberately narrow: one candidate, the check records and evidence paths for the cell it belongs to, the structure information it needs, the validation block of the relevant companion document, the procedure for promoting evidence, the boundary between source and local execution, the schema of the three verdicts, and earlier records with the same fingerprint. Other verifiers’ conclusions are not shown. Its job is as follows.
Figure 2. Follow one candidate and there are three pairs of eyes that cannot see each other’s conclusions (hunter, verifier, final verifier)
- Re-read every cited source location and confirm the path truly starts at a low-trust entry point and ends at the claimed sink.
- Rebuild the strongest control visible along the path. The rebuttal starts at this point.
- For a confirmed candidate, reproduce the minimal observable result directly when it is safe to do so.
- Check that likelihood, impact, confidence and the proposed fix match the evidence.
- For a
needs_validationcandidate, judge whether the reason it is blocked really lies beyond the source and local observation.
The verifier returns its conclusion without prose, in a single {"decision": "confirmed|needs_validation|rejected", "record": {...}} shape. The definitions of the three verdicts and what must be in each are below.
| Verdict | Condition | Severity | What the record must contain |
|---|---|---|---|
confirmed |
The verifier independently built the whole path and has a bounded observed result | Yes | Root cause, intended behavior, conditions for it to hold, execution evidence, observed result, fix strategy, confidence (low, medium, high) and why |
needs_validation |
Exactly one deployment or runtime fact remains | None | Claimed root cause, path, evidence, why it is blocked, a plan to check locally or in the deployed environment |
rejected |
Source, local behavior, visible controls, no impact or an impossible premise refuted the candidate | None | Reason for rejection and the path followed |
Rejection records are not thrown away. They are kept so that the next run does not repeat a claim whose evidence has not changed. In the words of the source document, needs_validation is not “a parking lot for speculative ideas”: one item may leave exactly one gap, and a check plan for the local or deployment side must be applicable.
Severity combines likelihood and impact, each on five levels (informational, low, medium, high, critical), and overall severity cannot exceed the proven impact. Critical covers things like unauthenticated code execution, access to an entire data store and takeover of arbitrary accounts, while high covers cases that fully defeat a stated control and have a real consequence. The deciding question is whether the control was completely broken or only weakened, and if no concrete harm can be named, the instruction is to go down one level. There is also a line telling the agent not to invent a low-severity vulnerability for a run that ended clean. Fixes are proposed as “the smallest source change” and not applied to the source directly. The form states the invariant to preserve, changes things as narrowly as possible at the last point where the trust decision is made, and adds a regression test.
In phase 5, yet another new research agent checks the final confirmed and needs_validation records one by one. Its input is the structured record, not what the hunter wrote, and it returns verified or replace. A replacement that raises a verdict or materially changes the root cause, path or impact takes effect only after passing through a new independent verifier again. In the quick profile this check is folded into the single phase-3 verifier.
Scripts check the form, agents check the substance
Phase 4 is where the parent writes findings.json and immediately runs the validation script. The script is a dependency-free Node.js file with a simple call format.
Figure 3. The message format written in the source. Paths and pass counts are examples, and the result is exit code 0 or 1
The exit code is 0 for a pass and 1 for every other failure. The script does not read an input that is a symbolic link or not a regular file, rejects files over 5 MiB or not in UTF-8, caps array items at 1,000 (applied to every array, not only result records), nesting at 64 levels, and the errors reported at once at 100. report-schema.json is read from the same folder as the script, and the ledger validator (validate-coverage-ledger.cjs) limits itself to 10,000 units and 500,000 traversed values. The pipeline runs this validator after first creating the ledger, every time a cell is changed, and before writing the phase-6 report, and it assigns no hunters from a ledger that has errors.
A PASS does not mean the target is safe. What it confirms is only form and consistency (required fields, the order of path steps, duplicated fingerprints), and it cannot guarantee the content is right. Trust in the content rests on the independent verifier from the previous section and on human review. The order is set this way on purpose. Writing and validating findings.json is phase 4, the records are re-validated in phase 5, and only after phase 5 passes does phase 6 produce the prose of REPORT.md, FINDINGS-DETAIL.md and NEEDS-VALIDATION.md. The skill lists as an anti-pattern the prose coming first and the JSON being fitted to it, which lets the prose and the JSON disagree. REPORT.md puts the run profile and scope, budget, reviewed commit, sandbox state, whether a previous run was used, and the deferred and out-of-scope areas in its first section, followed by the security summary, the confirmed table with per-item detail, the needs-validation table, hardening notes, and finally the ledger summary and the final critic’s result.
The second run starts from the first run’s ledger
When the same repository is run again, the parent reads the previous coverage-ledger.json and findings.json in full and compares them with the current source. Whether the source is unchanged or changed decides the fate of each record.
| Previous record | Source unchanged | Source changed |
|---|---|---|
| Confirmed | Carried over with the same fingerprint. Placed on the hunters’ exclusion list and not reported again | Becomes a re-validation cell. The earlier verdict is not assumed, and it is not excluded from hunting |
| Needs validation | Carried over with the reason it is blocked, only if the current source supports the path | Work again |
| Deferred, blocked, out of scope | Always work again. Never used to suppress work | Always work again |
| Rejected | Suppresses only that same claim, with the same source and evidence | Reopens if the evidence changed |
The point to be most careful about is that a previous ledger from a quick run or a scoped run does not mean “the rest is fine.” A ledger that is incompatible or missing is recorded as absent, not as “empty,” and no single run ever claims to have swept the whole target. The README’s statement that one run finds about half of what repeated runs find also assumes this ledger-carried repetition. Take an example (a scenario made up by our editors): you run an online-shop API through quick once on the day before launch. Cells the critic found and postponed stay deferred, the first section of the report says “partial check,” and when you run standard after launch, those cells come back near the front of the work list.
The room that runs target code is locked by the OS
A hunter or verifier may have to run the target project’s build, tests and processes to confirm a candidate. The target can be someone else’s code, or code that cannot yet be trusted, so SKILL.md allows this execution only inside a sandbox enforced by the OS, and it requires all four conditions.
- No external network (an isolated loopback namespace only, if needed)
- An empty environment populated from an allowlist, and a
HOMEinside a temporary folder - The target and the toolchain are read-only, and writes go only to the assigned
scratch/ - Low limits on CPU, memory, process count, file size, disk and run time
If even one cannot be enforced, the target code is not run, and the capability it could not confirm is written as the blocking reason of a needs_validation item. Dependencies are not installed, and builds are not left to download them. Only dummy principals and dummy secrets are used, and production endpoints, shared infrastructure, other people’s data and paid API quotas are not touched. It is also a rule to stop at the smallest local result that makes the candidate hold, and not to expand.
A file made in the temporary folder does not become evidence immediately. Trusted code on the parent side sets an allowlist and per-file and cumulative byte limits, does not follow symbolic links when it opens and reads files one by one, and rejects symbolic links, FIFOs, device files, hard links, directories and files whose size changes while being read. A file that fails to move is not accepted as evidence. The only place agents and the target process can write is scratch/, and the evidence folder (artifacts/) is managed by the parent alone. An audit that only reads source runs fine without this room. Without a sandbox, candidates that can only be confirmed by running simply stay in needs_validation.
Profiles and budget set the size of the pipeline
Because the design spawns many agents in parallel, the number of calls can grow fast, and there are two controls.
| Profile | Used for | Behavior |
|---|---|---|
quick |
Small targets, re-runs, a fast first check | One hunter wave and one critic pass. One verifier per candidate does both validation and final verification. Extra cells the critic finds are deferred. Cells are lumped together as surface × boundary × attack class |
standard (default) |
General audit | The full flow in the document. The critic repeats until clean, with a separate critic at the end |
deep |
Important or large targets | Cells are split into subsystem × lifecycle. Different fresh agents do validation and final verification. Cells already covered from the same source get an independent second pass |
A profile changes only breadth and redundancy, not the evidence standard. The candidate bar, the execution boundary, the needs_validation discipline, schema validation and independent verification of confirmed records are the same in every profile. A scoped run that looks only at certain paths or subsystems, a companion-document area, or the changes between two commits marks everything outside the scope out_of_scope and does not count it as “checked,” and scoped runs and quick runs must state “partial check” in the report.
The budget is the maximum number of agent calls across all phases. The skill sets aside shares before hunting starts.
- Reserve the share for 4 recon agent calls, the critic (1 call for
quick, 2 for the others) and at least 1 verifier call. - Assign hunters to the highest-priority cells with the remaining share, and push the overflow to
deferred. - After each wave, before starting the next one, check again that the critic and verification share is still there, and shrink the wave if it is not.
- If there are more candidates than verification share, stop hunting and verify in fingerprint order. Candidates that could not be verified stay
candidateand do not appear infindings.json.
If you run one authentication folder in deep with a budget of 40, 4 recon, 2 critic and 1 verifier are reserved first, so 7 come off the top and 33 go to hunters and candidate verification (our editors’ calculation). If the minimum share cannot be afforded, no agent is launched at all, and it asks for one of a bigger budget, a narrower scope or a different profile. If you proceed anyway, run_status is recorded as incomplete with the exact reason, such as budget_cannot_fund_reconnaissance_and_reserves. It is a device that prevents hiding the fact that the run stopped for lack of budget and saying “fully checked.” The skill has no separate fee, and costs go out as the host agent’s tokens or subscription quota, so the profile and scoping are what drive cost most.
Two numbers from the in-house harness, and the candidate funnel
The numbers in the public skill and in Cloudflare’s blog do not come from the same thing. The blog’s figures are values from the in-house harness (VDH for discovery, VVS for validation and fixing) sweeping 128 repositories, and that harness is a continuous pipeline that adds gap filling, deduplication, tracing that spreads to dependent repositories, feedback and reporting on top of recon, exploration and validation. The blog says only that it expects the harness itself to follow soon, and gives no date. Cloudflare’s explanation is that growing the skill for about six weeks produced this harness.
Figure 4. Before and after for two rates the in-house harness reported. The authors attribute the drop in rejection rate to a better way of injecting recon context
The rejection rate falling from 40% to 11% means the candidates hunters file got better, and the lower it is, the less waste there is in validation. The high-confidence share rising from 35% to 58% is the same direction seen from another side. These values have to be read as a time series from an in-house system with improved recon-context injection, not as “the rates you get by running the public skill as is.” The same post also contains a design principle that each agent uses less than 25% of its context window, the observation that hunters called the static analysis tool Semgrep zero times in a month, and the value that the “wishlist,” where hunters write down tools or resources they need but do not have, was the most-used tool, with 25,472 entries written across 128 repositories.
The funnel the candidates went through was reported as follows. The in-house harness produced 20,799 raw candidates, about 12,057 passed validation, and the central pool of 13,841, where results from other harnesses joined, split into 7,245 actionable, 5,442 duplicates and 1,154 reclassified.
Figure 5. The top two bars are the in-house harness’s candidates, and the bottom bar is the breakdown of the pool that other harnesses joined (the three values add up to the whole pool)
The two upper bars and the lower bar are not one continuous stream. The pool contains results from other harnesses, so jumping straight from 12,057 to 13,841 is not a valid calculation. What the bars do show is that nearly 40% of the pool (5,442) is duplicates, so a dedicated deduplication agent shrinks the candidate volume a lot. The limits the blog states about itself should be read alongside. It does not claim a rate of missed vulnerabilities (false negatives), because there is no ground-truth set with every real bug labeled. The numbers are a snapshot at the time of writing, the result of isolated research experiments in a test environment, not a count of unpatched vulnerabilities in production. The example of about 30,000 lines of code, 100 candidates becoming 80 after cleanup, and about 14 hours from discovery to a fix request is a realistic scenario drawn up, not a single measurement, and the fix agent does not merge anything: a human reviews every branch.
64 open pull requests show the repository today
Opening the GitHub repository again on Oct 27, 2026 (UTC), the core is exactly as it was on Sept 14. Since the first commit on June 18, 14 commits have accumulated; the latest, on Sept 14, explains guidance mode and full audit mode separately, and on Sept 10 the workflow, the result format and the validators were reworked from start to finish. A folder-structure fix on June 24 (npx skills add compatibility), path-order validation on July 2 and the memory safety and binaries companion document on July 4 came in as outside contributions, and on July 6 the AI and LLM, web protocols and auth, and clients companion documents were added. There are no releases, 48.2k stars, 3.0k forks and 180 watchers.
What has changed is outside the core. There are 64 open pull requests, 8 closed ones and 34 open issues, and the numbers climbed from 91 to 113 between Oct 21 and Oct 26 alone. The content stands out, because a good share of it aims at the skill’s own boundary.
- An issue (#94) that the target repository’s name steers the output path and the reuse of a previous run, which could cause path escape or contamination from a previous run, and the pull requests answering it (#95, #96)
- A proposal (#108) to treat the target repository’s contents as untrusted input in every agent prompt
- Two items (#102, #103) to make the validator reject JSON where the same key appears twice, and an item (#107, #111) to add a 1,000-field limit on objects to the
findings.jsonvalidator - Fallback paths (#99, #113) so the validator also runs on platforms without
O_NOFOLLOW(Windows) - A crypto and key-management companion document (#101), a
plugin.jsonfor agent plugins (#110), and a proposal (#109) to split fix design off from the discovery phase into a separate read-only phase
This list shows where the skill sits. The thing being audited is untrusted code, and that code’s repository name and file contents are the material that ends up in agent prompts and output paths. The rule “separate the side that finds from the side that grades” protects the independence of the verdict, but the path by which input the target sends back to the audit tool shakes the tool has to be closed separately. The issues and pull requests above are people finding and plugging that very entrance, and with no commits merged since Sept 14, they are still piling up open. So when you read a report produced with this skill, which copy (commit) of the skill you used and which folder you wrote the output to is as much the basis for interpretation as the confirmed table.