Vulnerability research
SkillSecurityHow to find, confirm, and report a security vulnerability with an AI session — in this repo's own sandbox boundary, in a dependency, or upstream. Activate when the user asks to "find vulnerabilities", "look for a bypass", "attack the sandbox", "audit this for security bugs", "is this exploitable", "write up this finding", or when a scanner, eval, or audit produces a candidate finding you are about to escalate. Also activate before you open a security advisory, file an upstream security report, or claim a boundary is bypassable. Covers reproduce-before-report, scoring a candidate against THIS threat model instead of a generic pattern, corroborating with the classical tools already wired into this tree, independent refutation before escalation, the maintainer-burden rule that bounds what you send upstream, and why a human sees every finding before anyone outside does. The load-bearing rule is that a finding you cannot reproduce is not a finding.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Vulnerability research skill
What this skill tells your AI
The instructions your AI receives, as published by alexandermattturner/agent-glovebox in .claude/skills/vuln-research/SKILL.md and read by ahel’s review.
The load-bearing rule
A finding you cannot reproduce is not a finding. It is a hypothesis, and it stays one until a command you can name turns it into evidence. Report the hypothesis as a hypothesis or drop it — never as a vulnerability.
This is the rule the whole activity hangs off, because the economics run against you. Generating a plausible vulnerability narrative is cheap and verifying one is expensive, so an unverified report moves your cost onto whoever reads it. The curl project watched its confirmed-vulnerability rate fall from over 15% to under 5% as unverified AI reports arrived, and closed a seven-year bug bounty on 31 January 2026 rather than keep paying that tax. The recovery is the instructive half: by April 2026 the slop had stopped and the AI-assisted reports that replaced it were mostly valid, because reporters started verifying before sending.
Scope this skill holds
This skill fires when the deliverable is a claim about real software being exploitable. That is a different job from the reviews this tree already has, so pick the right one and do not run two:
- A pending diff before a PR →
peer-review. - A single-pass look at the current branch → the built-in
security-review. - A whole-codebase multi-axis audit ending in a fix plan →
parallel-audit. - Proving an isolation layer still engages, with tests →
stress-test. - A vulnerability claim you intend to act on or send somewhere → this skill.
Deliver the finding set you were asked for. Do not widen a bounded question ("is this one path exploitable?") into a full audit.
1. Read the threat model before you read the code
Score every candidate against SECURITY.md, not against a generic vulnerability pattern. This tree states its threat model explicitly: the agent itself is the attacker, and it assumes that agent can run any shell as glovebox-agent, read its own guardrails, and spawn sub-agents. It also states what is out of scope — outside attackers, host compromise, base-image supply chain, deliberate bypass flags, and post-session merged code.
A candidate that lands in the out-of-scope list is not a finding here, however real it is elsewhere. Say so in one line and move on. A candidate that restates something already in SECURITY.md § Known limitations is not a finding either — that file already documents the deny rules as speed bumps, the LLM monitor as defense-in-depth rather than a boundary, and the audit log as tamper-evident rather than tamper-proof. Claiming any of those three as a discovery is the most common way to waste a reviewer's afternoon.
The question that earns a finding: does this break a claim SECURITY.md actually makes? Name the claim, quote it, then show the break.
2. Reproduce it, with a command that fails
Build the smallest artifact that demonstrates the break, and state the command that runs it. What counts, in descending order of strength:
- A test that goes red on the current tree and green once the hole is closed. This is the standard
writing-testssets for non-vacuity, and it applies here unchanged. Follow that skill for the mechanics. - A transcript of the real boundary refusing or failing to refuse — a live
sbxegress probe, an audit-log entry, a hook verdict..github/workflows/sbx-live-checks.yamlis where this tree runs that class against real KVM. - A worked trace through the code with every branch quoted. Weakest, and admissible only when you say plainly that you could not execute it.
Say which of the three you have. "Ran X, saw Y" and "expect Z because the code reads this way" are different epistemic states, and root CLAUDE.md § Supervision-legible work requires you to keep them apart. A finding at level 3 that you present at level 1 is the failure this skill exists to prevent.
When the boundary cannot run where you are — no /dev/kvm, no sbx binary — do not silently drop to level 3 and call it confirmed. Dispatch the live check that has the hardware, per the ci-triage skill, and say what you dispatched.
3. Corroborate with the tools already wired in
Do not re-derive by hand what a tool in this tree already answers. The winning AIxCC systems were hybrids — Team Atlanta took first place in August 2025 with classical fuzzers and symbolic execution feeding language-specific AI assistants, and the competition's own lesson was that when one method faltered another caught the bug. Reasoning alone is the weakest leg of that tripod.
What is already here, and what each answers:
| Question | Tool | Where |
|---|---|---|
| Does this pattern appear elsewhere in the tree? | bandit, plus ast-grep over this repo's own ruleset | .github/scripts/sast-scan.sh, glovebox-monitor/src/monitorlib/astgrep-rules.yml |
| Is this a known CVE in a dependency? | osv-scanner | .github/scripts/deps-vuln/scan.sh (osv-scanner.toml is the accepted-advisory list, currently empty) |
| Is this a known CVE in the guest image? | grype | .github/scripts/grype-scan.sh (.grype.yaml is the ignore list) |
| Does a data-flow path reach this sink? | CodeQL | .github/workflows/codeql.yaml |
| Would a test have caught this? | Stryker, cosmic-ray | .github/workflows/mutation-testing.yaml |
| Does the parser survive hostile input? | Hypothesis over the untrusted-input parses and the landing simulation | .github/workflows/fuzz.yaml |
A finding that one of these already reports is not yours to re-file — check first. A finding that contradicts one of them is interesting, and the contradiction goes in the report.
The monitor's own write-scan covers less than its audit entry suggests, so never read a clean static_scan record as coverage. It runs only on Write/Edit/MultiEdit (staticscan.py's _SCANNABLE_WRITE_TOOLS), so code written through bash — a heredoc, tee, sed -i — is never scanned, in any mode. It does not run at all under --permission-mode auto, where core.main returns at its PermissionMode.AUTO branch before reaching the scan — and sbx is always auto. It records only high- and medium-severity findings, so findings: 0 means none at those tiers, not none seen. Run .github/scripts/sast-scan.sh over the tree when you need the ruleset's real reach.
4. Refute before you escalate
Before a finding leaves this session, spawn one general-purpose sub-agent whose brief is to refute it. Give it the reproduction and the threat-model claim, and tell it to default to "refuted" when the evidence is ambiguous. One agent, not a panel — reach for three only when the finding would trigger a public advisory.
This is not a re-read of your own reasoning, which root CLAUDE.md and prompt-authoring.md both tell you to skip. It is a fresh reader who never saw you build the case, which is the independence peer-review buys. Cite the model tier from root CLAUDE.md § Delegation: an adversarial review is Opus, high.
Know what the refuter cannot do for you. It shares your training and your failure modes, so it catches an invented detail, a broken chain of reasoning, and a line you misread. It does not catch a misconception you both hold about how this system works. Two models agreeing is therefore weaker evidence than two people agreeing, and it never upgrades a level-3 trace into a level-1 reproduction. The reproduction is what substitutes for expertise the reader may not have — a command that goes red is checkable by someone who cannot audit your argument, and this project's maintainer has said plainly that they cannot.
Record the refuter's verdict in the report even when it agrees with you, and record it as one model's opinion.
5. Bound what you send outside this repo
A report to an upstream maintainer costs their time, not yours. OpenSSF and OpenJS both converged on the same reporter-side rules in 2025 and 2026, and they are cheap to follow:
- Send a private proof of vulnerability, and a proposed patch where you can write one.
- Give reproduction steps that run, and impact stated against that project's threat model.
- Never send a finding you have not reproduced, and never send a speculative pattern match.
Never open a public issue, advisory, CVE request, or upstream security report yourself. SECURITY.md routes findings through a private advisory, and the human decides what goes outside. Big Sleep works this way too — the agent flags, a human researcher verifies, and only then does the bug move. Write the report, put it in the PR body or in chat, and say it is ready to send.
This is the one place in this tree where "ask first" beats the autonomy default, and root CLAUDE.md § Autonomy already carves it out: disclosure is outward-facing and irreversible.
6. Write the report
300 words maximum per finding. Longer is not more rigorous; it is less read.
Each finding carries exactly these, in this order:
- The claim it breaks — quoted from SECURITY.md, with its heading.
- The reproduction — the command, and which of the three evidence levels it reached.
- What an attacker gets — in one sentence, against this threat model.
- The refuter's verdict.
- The fix, or the reason you did not write one.
Nothing else. No severity theatre, no CVSS vector you derived by feel, no restatement of what the subsystem does. If a detail would not change what the reader does next, cut it.
A finding that reads right:
Breaks: SECURITY.md § Defense layers 1 — "the removal of an old host-wide policy file leaves no trace of glovebox behind." Reproduction: level 1. A dangling parked symlink under
managed-settings.d/makesPath.is_file()read False, sobin/lib/uninstall_settings.py's_teardown_settings_filereports it removed without deleting the link. Impact: the stale link keeps shadowing the path Claude Code reads, soclaude-originalstill runs a hook pointing at a checkoutglovebox uninstalldeleted. Refuter: confirmed — reproduced independently against a fresh dangling symlink. Fix: checkis_symlink() and not exists()before theis_file()guard, and add the regression test above.
And one that does not, for contrast — this is the shape to delete:
The credential handling in the monitor appears potentially insecure. An attacker might be able to access sensitive material under certain conditions, which could have serious security implications. Recommend reviewing the permission model. Severity: HIGH.
It names no claim, runs no command, and gives the reader nothing to check.
7. When you find nothing
Say that, and say what you covered. A clean result with a named surface is a real deliverable — it tells the next session where not to look again. Numbers over adjectives: "checked whether a resume can be pointed at another workspace's transcript — the archive is workspace-keyed at both capture and restore, so it cannot" beats "the resume path looks fine."
Never pad a clean run with a speculative finding to make it look productive. That is the slop failure with extra steps.
Signals
- GitHub stars
- 63
- Forks
- 11
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
vuln-research- Source
- github.com/alexandermattturner/agent-glovebox