This skill should be used when the user says "scan for CVEs", "CVE scan", "check for vulnerabilities", "find vulnerabilities", "check security advisories", "dependabot triage", "dependabot scan", "scan dependencies for security issues", "audit dependencies", "vulnerability triage", "security scan", "run security audit", "arness CVE scan", "arn-code-batch-cve-scan", "run a scheduled CVE scan", "produce a CVE proposal", "finalize a CVE proposal", or wants Arness to discover, triage, and ticket security advisories across project dependencies. Supports three modes (interactive, proposal, finalize) so the workflow is safe to schedule unattended via Claude Code Routines and tool-agnostic enough to drive headlessly via claude -p or any LLM-running CLI. Dual-source discovery (GitHub Dependabot plus locally-detected scanners), per-CVE triage via arn-code-cve-analyst, project-native waiver capture, and pre-triage parent plus per-group sub-issue ticketing on GitHub or Jira. Reads from the configured Security branch.
75
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Discover, triage, and ticket security advisories across project dependencies. Dual-source CVE discovery (GitHub Dependabot + locally-detected scanners), per-CVE triage via the arn-code-cve-analyst agent, project-existing waiver capture, and pre-triage parent + per-group sub-issue ticketing. All scanner / waiver / tracker detection is evidence-based — this skill never enumerates tool names; everything delegates to <code-patterns-dir>/security-scanning.md (written by Phase 1's codebase-analyzer extension).
Three modes (--mode=<value>):
interactive (default): full ergonomics, inline ticketing, prompts for waivers, AskUserQuestion available.proposal: ZERO user prompts, ZERO writes to GitHub / Jira / project waiver files; emits a CVE_SCAN_PROPOSAL.md + .json sidecar that finalize mode consumes. Safe to schedule via Claude Code Routines or claude -p headless.finalize: reads a previously-emitted proposal, walks needs-review items via AskUserQuestion, applies deferred writes behind a single consent gate.This skill is a sequencer — it MUST NOT duplicate sub-reference logic. All procedural detail lives in references/. The body below names the steps and points to the right reference.
Pipeline position:
arn-code-codebase-analyzer (security-scanning.md)
│
▼
**arn-code-batch-cve-scan** (3 modes)
│
dispatches per-CVE
│
▼
arn-code-cve-analyst (per-CVE triage)
│
▼
Ticketing (interactive / proposal-render / finalize-POST)
│
▼
arn-code-batch-cve-fix (consumes tickets)Read ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-ensure-config/references/step-0-fast-path.md and follow its instructions. This guarantees ## Arness is configured with Arness Code fields.
After ensure-config completes, extract from ## Arness:
enabled | none | skip. If none or skip, inform the user: "Security scanning is set to <value>. Update the Security scanning: field in ## Arness to enabled to run this skill." STOP.auto. If auto, resolve via git symbolic-ref --short refs/remotes/origin/HEAD. This is the branch the skill scans (NEVER the working tree).security-scanning.md.github | jira | none. Drives the ticketing or no-tracker-fallback branch.github | jira | none. Used for visibility detection.If Security scanning: or Security branch: is missing, Layer 2c will have prompted the user via AskUserQuestion and written the chosen value (see Phase 5 wiring). This skill consumes the field — it does not write it.
If <code-patterns-dir>/security-scanning.md is missing, inform the user: "Security scanning is enabled but security-scanning.md was not found. Re-run arn-code-ensure-config or invoke arn-code-codebase-analyzer directly to generate it." STOP.
Read ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/modes.md and follow its CLI parsing procedure. Set the mode variable (one of interactive, proposal, finalize) used throughout the rest of the skill.
The hard rules per mode are the canonical contract every other reference must satisfy. If you find yourself unsure about reachability of AskUserQuestion or write semantics at any later step, return to modes.md.
Read ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/stale-db.md and follow its procedure. Mode-aware:
interactive: prompt the user for --allow-stale-db justification on stale DB.proposal: refuse without prompting; record needs-review: stale-db in the proposal; exit non-zero so the scheduler flags the failure.finalize: not relevant (finalize works against the proposal's frozen scanner output).Validate that <security-branch> exists on the remote:
git ls-remote --exit-code origin "<security-branch>"If the branch is missing:
interactive: prompt the user for a corrected branch name (AskUserQuestion).proposal: write needs-review: branch-missing to the proposal and exit non-zero.finalize: not relevant.This validation runs only in interactive and proposal modes (finalize consumes a frozen proposal that already passed this check).
Skip in finalize mode (the proposal already contains the frozen discovery output).
Read ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/discovery.md and follow its dual-source procedure. Discovery is read-only and identical in interactive and proposal modes.
All manifest and lockfile reads MUST go through git show <security-branch>:<path> — NEVER the working tree.
Apply the dedupe key (advisory-id, ecosystem, package, installed-version) to merge the two sources into a unified CVE list. Procedure detailed in references/discovery.md (Dedupe section).
Skip in finalize mode.
Read ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/parser.md and follow its procedure. Extract version-bound fields (installed-version, fixed-version, vulnerable-range) per scanner's documented JSON schema. Compute and store the SHA-256 checksum of each raw scanner output (sha256sum || shasum -a 256) — the triage agent echoes this checksum back to prove input integrity.
The parser is the strict boundary: the arn-code-cve-analyst agent annotates contextual fields ONLY and NEVER re-derives version bounds.
Skip in finalize mode.
Read ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/triage-dispatch.md and follow its dispatch procedure. For each CVE, dispatch the arn-code-cve-analyst agent via the Task tool, passing the model from .arness/agent-models/code.md as the model parameter (see plugins/arn-code/skills/arn-code-ensure-config/references/ensure-config.md "Dispatch convention" for fallback).
Mode-aware graceful degradation: if the LLM runner does not support subagent dispatch (opencode, some claude -p configurations), fall back to inline reasoning in the main loop. This preserves tool-agnosticism.
Skip in finalize mode (triage records are already in the proposal).
Before any ticketing writes, query open issues with the arness-security label and build the existing-CVE set. Dedupe key: (advisory-id, status).
existing-ticket: #N so finalize's POST step can skip them.existing-ticket is null.For Jira: same logic using the configured Jira project's open issues filtered by the arness-security label.
Branch on mode:
interactive ModeRead ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/ticketing.md and follow its interactive-branch procedure. Writes ticketing inline. Prompts for waivers via AskUserQuestion.
If Issue tracker: none, instead read ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/no-tracker-fallback.md and follow its procedure (writes CVE_RESOLUTION_PLAN.md under a per-scan dated directory).
Then read ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/waivers.md (interactive branch) for any approved waiver writes, and ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/visibility.md for default-redacted summary handling.
proposal ModeRead ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/proposal-artifact.md and follow its rendering procedure. Render the fully-formed ticket bodies, waiver needs-review entries, and visibility decisions into the proposal artifact's Markdown surface AND JSON sidecar.
Per the canonical contract in modes.md: this mode emits ZERO AskUserQuestion invocations and ZERO writes to GitHub / Jira / project waiver files. Waiver actions are ALWAYS noop in proposal mode (per spec FR §24; documented in references/waivers.md).
Also write CVE_RESOLUTION_PLAN.md per references/no-tracker-fallback.md IF Issue tracker: none — it lives alongside the proposal artifact in the same per-scan dated directory.
finalize ModeRead ${CLAUDE_PLUGIN_ROOT}/skills/arn-code-batch-cve-scan/references/finalize.md and follow its re-entry procedure. Load the proposal (default: most recent under .arness/plans/CVE_*/; explicit via --proposal-path=<...>). Walk needs-review items via AskUserQuestion. Apply pre-rendered ticket bodies and confirmed waiver writes behind a single consent confirmation gate.
When mode == "proposal" AND the proposal artifact was written successfully:
Emit a single stable stdout line so schedulers (Claude Code Routines, cron + claude -p, etc.) can detect completion machine-readably:
arness::cve-scan::proposal-ready path=<absolute-path-to-CVE_SCAN_PROPOSAL.md>This line MUST be emitted exactly once, AFTER all writes are flushed and AFTER the atomic .tmp → mv rename completes. Schedulers parse this line to attach the artifact to a notification or to chain into a finalize invocation.
In interactive and finalize modes, no stable stdout completion line is emitted — those modes complete with a human-facing summary.
This skill supports unattended scheduled invocation. Recommended mechanisms:
--mode=proposal, attaches the emitted proposal artifact (parse the arness::cve-scan::proposal-ready line), and notifies the user. On user response, invoke a follow-up routine with --mode=finalize --proposal-path=<...>.claude -p headless (tool-agnostic) — for users on opencode, Aider, or other LLM-running CLIs, or for users wiring into external schedulers (cron, GitHub Actions, etc.). Invoke claude -p "/arn-code-batch-cve-scan --mode=proposal"; capture stdout; grep for arness::cve-scan::proposal-ready path=; attach the artifact to the desired notification channel.Both paths inherit the same idempotency + diff-mode behavior — re-running a scan against the same scanner output is a no-op (subject to the (advisory-id, status) dedupe key from Step 8). This skill ships NO built-in scheduler.
7f87870
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.