$ adversarial scan . --agent
The agent you already have is the infrastructure
Keyless adversarial scanning: deep triage through the AI coding agent already installed and authenticated in your environment. No API keys, no tenant signup, no second bill — and no code leaving the machine.
Published 2026-09-05
# the problem
Procurement is a security boundary
Every CI security tool you evaluate wants the same things before it scans a single line: an account, an API key, a tenant, a pricing conversation. That's friction, and it's not just annoyance — it's a boundary. Teams run un-scanned code for weeks because the approval for "yet another security SaaS" is still sitting in someone's queue. Meanwhile, the thing those tools charge you to rent — a capable model reading your code and judging it — is already sitting in your environment. Your engineers run AI coding agents locally, already authenticated, already trusted with the codebase.
So we asked a blunt question: if the model is already there, why are
you renting another one? Keyless agent mode is the answer.
adversarial scan --agent runs the deep-triage half of the
scan through whichever agent CLI it finds on PATH —
Claude Code, Codex, Gemini, OpenCode, or Cursor's
cursor-agent, probed in that order. The CLI never
contacts /api/scans in this mode, never sends file
contents anywhere, and works fully offline.
# how it works
Deterministic candidates, judged locally
The split of labor is deliberate: the machine does what machines do reliably, and the agent does what requires judgment.
-
The regex engine proposes
The offline regex engine — compiled from the same pattern data as the attack library's 56 validated techniques across 10 categories — scans the target files and emits candidate findings. This part is fully deterministic: same input, same candidates, every time.
-
The agent disposes
Each candidate is handed to the local agent with the library's own context: the technique's
prompt_templateandmitigation, plus the matched file snippets. The agent reads the actual code and replies with a JSON verdict array — one object per candidate, verdictconfirmedorrefuted, with evidence and severity. -
The CLI merges — conservatively
A refuted candidate is dropped. A confirmed candidate becomes a finding. A candidate the agent never returned a verdict for is kept, not cleared. Agent silence can never produce a false pass.
# Scan the current directory; use the first agent found on PATH
$ adversarial scan . --agent
note: running deep triage via 'claude'
# Pin a specific agent (use = so the name isn't swallowed as a path)
$ adversarial scan . --agent=codex
# Paths precede --agent: the flag's value is optional
$ adversarial scan src/ .github/workflows/ --agent
# Agent verdicts come back as a strict JSON array
[{"id":"ADV-0013","verdict":"confirmed",
"evidence":"checkout runs untrusted code from the fork","severity":"critical"}]
$ echo $?
Exit codes you can gate on
Keyless mode keeps the same contract as every other scan, so jobs gate the same way:
0 — clean
Every candidate was refuted by the agent (or there were none). The merge produced no findings and no triage-only matches.
10 — triage-only
The only matches are triage-class techniques — ADV-0013 (pull_request_target handling) or ADV-0024 (poisoned agent config). These always exit 10 regardless of what the agent says; they need a human, not automation.
11 — finding
At least one candidate was confirmed (or never refuted). Fail the job, read the evidence, fix the code.
2 — usage error
You named an agent that isn't installed (--agent=codex with no codex on PATH). Configuration problem, distinct from scan results.
And the failure mode that matters most: if the agent crashes, times out, or returns malformed output, the scan doesn't die and it certainly doesn't pass. It falls back to regex-only results and says so on stderr:
warning: agent triage failed ('gemini' timed out); falling back to regex-only results
The regex candidates are still reported and still gate the exit code. A broken agent degrades the signal; it never silences it.
$ adversarial scan . --agent --with-skills
Point the agent at the skills pack
The paid skills pack — 134 SKILL.md skills across
15 categories — installs into .agents/skills/ in your
repo. With --with-skills, the CLI appends a summary of
each installed skill to the triage prompt, so the local agent judges
candidates with adversarial-method context it wouldn't otherwise have.
The entitlement model matches the threat model: access is enforced at install time (that's what your subscription is for), and execution stays entirely local. The skills, the snippets, and the verdicts never leave the runner. Nothing about keyless mode changes that — there is still no API key to manage and no hosted model in the loop.
# drop-in CI
One script in the workflow
scripts/ci-scan.sh is the CI entrypoint: it detects a GitHub Actions PR context and checks out the PR with gh pr checkout, limits the scan to files changed versus the base ref when BASE_REF is set, and passes the scan's exit code straight through for job gating.
# .github/workflows/adversarial.yml
name: adversarial-scan
on:
pull_request:
types: [opened, synchronize]
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # need history for the diff vs base
- name: Keyless adversarial scan
env:
BASE_REF: ${{ github.base_ref }}
run: scripts/ci-scan.sh
# exit 11 (finding) or 10 (triage-only) fails the step;
# exit 0 passes; exit 2 means the named agent isn't installed
No ADVERSARIAL_TOKEN, no secrets block, nothing to rotate.
The only credential involved is the one your agent CLI already has —
and it authenticates to its own service, not to us.
# why keyless
The shortest path to scanned code
The hosted scan API isn't going anywhere — if you want findings triaged by our models, with patches proposed and PR comments posted, that's what the platform does. Keyless mode is for the other case: the team that wants the library's 56 techniques running on every pull request today, without waiting on procurement. One CLI install, one workflow step, one agent your team already runs. The attack library does the detection; the infrastructure you already pay for does the judgment; the exit code does the gating.