Skip to content
Like what we’re building? Star on GitHub

Security bots — sec-audit-source (Seki) + sec-audit-deps (Depsy) ​

This page covers the two manual audit bundles — CLI-launched, whole-tree or diff_base-scoped, reporting to the kanban board. For the push-driven supply-chain shields that gate every PR/push — supply-shield (Shieldy, malware axis) and supply-shield-cve (Vulny, CVE axis), diff-scoped by default and reporting back onto the forge (sticky comment + inline reviews + SARIF) — see their run bilans (supply-shield.md, supply-shield-cve.md).

Iterion ships two complementary manual audit bundles. They share a threat-model vocabulary, kanban label conventions, and FP-memory discipline, but address different layers of the application.

BundleCodenameRoleInspired by
sec-audit-sourceSekiSource-code audit + verified remediationvercel-labs/deepsec, anthropics/defending-code-reference-harness
sec-audit-depsDepsyInstalled third-party dependency auditSocialGouv/no-package-malware

When to run which ​

Run both as part of pre-release hardening, or pick the one matching the threat you're chasing.

Seki — what landed in this branch ​

Seki was previously an audit-only bot (scanners → triage → single-judge revalidate → kanban). This branch turns it into an audit + verified remediation bot. Six new capabilities, all in bots/sec-audit-source/main.bot:

#CapabilityVars (default)Skill
1Project security context — .sec-audit/context.md (threat model + auth model + known-FP sources). Loaded or auto-generated on first run; injected into triage + every voter prompt as authoritative scoping (NOT instructions).enable_project_context=true, context_path=…/.sec-audit/context.md, context_ttl_days=90, force_context_refresh=falseproject-context.md, threat-model.md
2N-vote adversarial revalidation — the single judge becomes a fixed pool of 3 independent "disprove" voters (all three default to claude_code + claude-opus-5 — opus-first out of the box; restore cross-family diversity by overriding the per-voter model/backend env vars, or the opt-in ITERION_SEC_AUDIT_PROVIDER_CHAIN GLM lane). Majority drives the verdict; await: best_effort tolerates one crashed voter. Voters consult git log/git blame for fixed_recently / introduced_recently signals. Unanimous dismiss with a cited guard appends to fp-known.yaml.confirm_threshold=2, fp_append_policy="unanimous_dismiss"disprove-voting.md
3Diff/incremental mode — when set, scopes triage to files changed between the working tree and git merge-base <diff_base> HEAD (mirrors code-review diff_precheck shape). Scanners still walk the whole tree; the narrowing happens at triage via file_filter. Empty = full scan.diff_base="" (try main, origin/main, or HEAD for uncommitted-only)(handled by diff_scope tool node)
4Optional deepsec scanner backend — runs deepsec init/scan/process/export headlessly from the workspace; the JSON is ingested by triage like any other scanner. Reuses the local claude subscription when no AI Gateway key is set. Requires the deepsec CLI on PATH and Node 22+. deepsec_root only names an optional reference clone used to diagnose a missing CLI; it is never executed as a fallback. ALWAYS exits 0 — a missing binary degrades gracefully.enable_deepsec=false, deepsec_concurrency=4, deepsec_process_limit=50, deepsec_root="${HOME}/lab/ai/references/deepsec"scanner-deepsec.md, see also references-bootstrap.md
5Integrated remediation phase — per confirmed finding: patch_author → build_rung → reproduce_rung (original scanner rule no longer fires) → regress_rung (tests pass) → reattack (fresh judge probes the vuln CLASS across the package) → reviewer_isolation (judge sees only {file, line, category, diff} — schema-enforced) → aggregate_verdict. In apply modes, verified patches commit to a temp branch iterion/sec-fix/<run-id>; apply_gated PAUSES on a human gate (iterion resume --run-id <id> --answer approved=true|false) before merging --no-ff to the user's branch; apply_auto skips the gate; propose only writes diffs. Crypto + secrets are always hard-stopped.remediate=false (opt-in), remediation_mode="apply_gated", hard_stop_categories="crypto,secrets", max_fix_per_run=10, patch_attempts=1, patch_dir=…/.sec-audit/patchessecurity-patcher.md, patch.md, reattack-oracles.md, reviewer-isolation.md, crypto-handling.md
6Env-overridable cost-tier backend — the whole bot runs on a Claude Code subscription with no API key by default (ITERION_SEC_AUDIT_BACKEND defaults to claude_code, models to claude-opus-5 — opus-first out of the box, so triage stops stalling on the heavy input). Flip the spine (triage/voters/report) to the metered claw + openai/gpt-5.5 / GLM lane via the env vars (or the opt-in ITERION_SEC_AUDIT_PROVIDER_CHAIN). detect_tech keeps its own cheap claw/gpt-5.5 default so flipping the spine can't drag the classifier onto an incompatible model.ITERION_SEC_AUDIT_BACKEND (claude_code), ITERION_SEC_AUDIT_MODEL (claude-opus-5), ITERION_SEC_AUDIT_VOTER_V1_MODEL / _V2_MODEL / _V3_MODEL (claude-opus-5), ITERION_SEC_AUDIT_DETECT_BACKEND (claw) / ITERION_SEC_AUDIT_DETECT_MODEL (openai/gpt-5.5), ITERION_SEC_PATCH_MODEL (claude-opus-5)(env overrides on agent/judge declarations in main.bot)

Deepsec 2.3.9 export ingestion ​

The real export is a bare array whose findings carry a [SEVERITY]-prefixed title, description, severity and labels at the root. labels begins with security, project:<projectId>, severity:<severity>, slug:<vulnSlug>, confidence:<confidence>; owning-team:<slug> entries exist only when the exporter supplied teams. filePath, lineNumbers, vulnSlug, confidence, runId, projectId, severity, discoveredAt and an OwnerSummary owners object are under metadata; every owner array may be empty (teams[] {name, slug}, oncall[] {name, email, …}, managers[] {email, …}, contributors[] {name, email, score, …}, and recentCommitters[] {name, email, date}). Root/owner assignee fields are exporter-derived only when oncall exists. Description starts with **File:** \<path>` (lines n, n, …), Project:, a Severity: / Confidence: / Slug:line, and an exporter-supplied## Ownerssection only when owner data exists, before## Findingand## Recommendation. Seki's [scanner-deepsec` skill](../bots/sec-audit-source/skills/scanner-deepsec.md) maps that schema to candidates from either the inline group or the published file.

cap_findings selects deepsec by the inode identity of the path in DEEPSEC_PATHS, not by basename, realpath spelling, or JSON shape. It severity-sorts and caps the export without trimming it, so metadata and descriptions over 300 characters survive both transports. HIGH_BUG sorts with HIGH, BUG with MEDIUM; all other scanners retain their existing trimming.

End-to-end on the subscription, no API key, with the default gated remediation:

bash
ITERION_SEC_AUDIT_BACKEND=claude_code \
ITERION_SEC_AUDIT_MODEL=claude-opus-5 \
ITERION_SEC_AUDIT_VOTER_V1_MODEL=claude-opus-5 \
ITERION_SEC_AUDIT_VOTER_V3_MODEL=claude-opus-5 \
  devbox run -- iterion run bots/sec-audit-source/main.bot \
  --var workspace_dir=$(pwd) \
  --var enable_deepsec=true \
  --var diff_base=origin/main
# When the workflow pauses on approve_fixes, inspect the temp branch then:
#   iterion resume --run-id <id> --answer approved=true   # merge to your branch
#   iterion resume --run-id <id> --answer approved=false  # abandon; temp branch kept

See security-patcher.md for the remediation phase in depth (ladder rungs, modes, temp-branch + human-gate flow, crypto/secrets hard-stop) and references-bootstrap.md for the optional deepsec/harness reference checkouts and ITERION_REFERENCES_ROOT. The executable prerequisites are the deepsec CLI on PATH and Node 22+.

The budget headroom is max_cost_usd: 150 per run (bumped 25 → 70 → 150) to absorb the 3-voter pool + a full remediation ladder on large repos; lower ITERION_SEC_AUDIT_EFFORT_VOTER to claw budget back on small repos.

Architectural patterns shared by both ​

Static signals → LLM with strict JSON schema ​

Both bots delegate pattern matching to deterministic tools (scanners or heuristic extractors) and use the LLM only for normalisation + reasoning + emission:

Rationale:

  • Determinism: scanner output is identical on identical input.
  • Coverage attribution: a missed vuln is traceable to a ruleset.
  • Cost: scanners are free; LLM tokens are not.

Three-voter majority for FP reduction ​

sec-audit-source sends fresh candidates through three independent adversarial disprove voters. majority_verdict confirms at confirm_threshold (2 of 3 by default), while a unanimous dismissal backed by a cited guard can append a reviewed false positive. See disprove-voting.md.

Cross-run memory ​

Each bot retains state between runs so it doesn't repeat itself:

BotMemoryLocationVisibility
sec-audit-sourceFalse positives.sec-audit/fp-known.yaml in the scanned repoCommitted; human-reviewable
sec-audit-depsPer-package verdictscache_path (default: out-of-tree run scratch; --var cache_path=$HOME/.iterion/security-cache/packages.jsonl opts into the host-wide store)Per-run by default; the host-wide opt-in is auto-mounted in sandbox via host_state: auto

The sec-audit-source FP memory is per-repo because false positives are pattern-specific: urlSafe(input) may guard an SSRF in repo A and miss in repo B. The sec-audit-deps package cache is portable across repos because a published name@version+checksum is universally identifiable — hence the host-wide cache_path opt-in (the scratch default exists because sandbox images pinning a non-host user cannot write the auto-mounted ~/.iterion tree).

Capability-gated board writes ​

The node that creates kanban issues declares the minimum capability set it needs:

report_card / llm_review:
  capabilities: [board.read, board.create, board.label]

Everything else (detect_tech, scanner tools, triage, revalidate, …) runs readonly: true without board capabilities. A capability-denied attempt to write the board surfaces as a hard runtime error.

Per-language extensibility ​

Both bots use skill-driven language coverage: one deterministic node enumerates detected ids and reads the machine block from each skills/lang-<id>.md. Adding a language or ecosystem means dropping a skill with its iterion:scanners (Seki) or iterion:heuristics (Depsy) block — no new tool node, router branch, or when has_<id> DSL edit. Depsy needs a parser only when the scanner's output shape is new.

V1 ships:

  • sec-audit-source: JS/TS, Go, Python + always-on generic (gitleaks
    • trivy + semgrep p/default).
  • sec-audit-deps: npm/yarn/pnpm, pip/poetry/uv, go modules + always-on generic.

Roadmap candidates: PHP, Ruby, Rust, JVM (Maven/Gradle), .NET (NuGet).

Kanban label conventions ​

LabelEmitted byPurpose
severity:<low|medium|high|critical>bothBucketing on the board
type:<finding-type>sec-audit-sourceOne of 12 from [[finding-taxonomy]]
type:supply-chain-<signal-id>sec-audit-depsPrimary signal that triggered the issue
scanner:<id>sec-audit-sourcePrimary scanner (semgrep, gosec, bandit, gitleaks, trivy)
ecosystem:<id>sec-audit-depsnpm, pypi, gomod
source:sec-audit-source / source:sec-audit-depsbothLets a remediation bot filter to security findings
triage-uncertainsec-audit-sourceRevalidate voters split or all uncertain; human review needed
patched:seki / patch-proposed:sekisec-audit-sourceRemediation phase landed a verified patch (committed/merged) vs only wrote a draft diff
seki-verdict:<verified|uncertain>sec-audit-sourceRemediation ladder outcome
seki-fix-pending / seki-fix-rejected:<reason>sec-audit-sourceapply_gated abandoned by operator / ladder rejected the diff
seki-hard-stop:<finding_type> + human-reviewsec-audit-sourceCrypto / secrets finding routed to human (never auto-patched)
patch-artifact:<path> / seki-temp-branch:<branch> / seki-merge-sha:<sha>sec-audit-sourceAudit-trail anchors written by remediation_report

A downstream remediation router can list issues via mcp__iterion_board__list_issues with labels: ["source:sec-audit-source"] to scope itself to security findings, and filter further on patched:seki / patch-proposed:seki / seki-hard-stop:* to decide whether human follow-up is still needed.

Comparison with deepsec ​

deepsec and sec-audit-source target similar problems with different ergonomics. Trade-offs:

Propertydeepsecsec-audit-source (Seki)
DistributionVercel AI Gateway + Vercel Sandbox; npx installSelf-hosted; bundled with iterion
Distributed executionYes (--sandboxes N --concurrency M)Sharded (shard_size > 0 dispatches N child runs); cloud queue fan-out via iterion's cloud mode
Matcher expressivenessProgrammatic TS plugins (full filtering / multi-pattern / per-file state)Scanner-based (semgrep / gosec / bandit / gitleaks / trivy) + custom programmatic matchers under .sec-audit/matchers/ + optional deepsec backend via --var enable_deepsec=true (see references-bootstrap.md)
Per-file append-only recordsYes (atomic locking, distributed-ready).sec-audit/files/<sha1(path)>.json — append-only history, scoped to single-process runs + sharded children
Project context fileINFO.md per project.sec-audit/context.md — auto-generated on first run via the harness-derived threat-model skill, committable, TTL-refreshed (context_ttl_days=90)
Diff / PR mode--diff origin/main--var diff_base=origin/main (merge-base scoped triage)
FP reductionrevalidate consults git history3-voter "disprove" majority + git-log/blame signal per voter (see disprove-voting.md)
Remediation / patchnone (scan only)Verification-ladder remediation phase (build → reproduce → regress → reattack → reviewer-isolation), three modes (propose / apply_gated / apply_auto), crypto/secrets hard-stop. See security-patcher.md
Operator-visible FP suppressionrevalidate verdicts in workspaceCommitted .sec-audit/fp-known.yaml (appended only on unanimous-dismiss + cited guard)
Integration with project boards / dispatcherNone built-inNative: each finding is a kanban issue, then remediation_report labels it with the per-finding ladder outcome
Budget headroomTuned for $1000s/scan large monoreposmax_cost_usd=150 per run (bumped 25 → 70 → 150 to absorb voters + ladder); cloud mode scales further

Comparison with no-package-malware ​

no-package-malware solves a different problem: it's a Verdaccio gateway that intercepts npm installs at the registry boundary. sec-audit-deps runs after the install, on the installed tree.

Propertyno-package-malwaresec-audit-deps
PositionIn front of npm install (registry proxy)Post-install audit
EnforcementFail-closed: blocks npm install of risky versionsAdvisory: surfaces issues, doesn't block install
Ecosystemsnpm onlynpm + pip + go modules (extensible)
StateMongoDB + Redis + Verdaccio + workersBundle-only (one JSONL file)
Org / token / budget modelYes (per-org Verdaccio tokens)None; runs on whoever invoked iterion run

Use both if you can: the gateway prevents known-bad versions from ever landing on disk; the audit-bundle catches what slipped through

  • provides a board-integrated remediation surface.

See also ​