security-cve-review

Inventory NuGet packages and Aspire-managed container/infra components, cross-reference them against OSV.dev, and assess which matched vulnerabilities are actually reachable in how this application us

SKILL.md

GitHub

Instructions

Contract: specs/008-adversarial-security-review/contracts/skill-commands.md (/security-cve-review) and contracts/osv-dev-api.md. Requirements satisfied: FR-003, FR-004, FR-007, FR-010, FR-011, SC-005.

1. Read trigger-mode config (FR-011)

Read specs/008-adversarial-security-review/review-config.json and check dependencyReview.trigger. Today the only valid value is "on-demand" — proceed for a manual invocation. If it's ever something else and this isn't a manual request, stop and tell the user.

2. Inventory dependencies (FR-003)

.specify/scripts/bash/security-inventory-dependencies.sh \
  --repo-root . \
  --out specs/008-adversarial-security-review/findings/.tmp-dependency-components.json

3. Query OSV.dev (FR-003)

.specify/scripts/bash/security-osv-query.sh \
  --components specs/008-adversarial-security-review/findings/.tmp-dependency-components.json \
  --out specs/008-adversarial-security-review/findings/.tmp-vulnerability-matches.json

If this step exits non-zero (OSV.dev unreachable), stop and report the error to the user — do not proceed to persist a partial or empty result as if the review completed cleanly.

4. Assess relevance (FR-004 — judgment call, this is the Agent-invocation step)

For each entry in .tmp-vulnerability-matches.json, use the Agent tool to assess whether the vulnerable functionality is actually reachable given how this application uses that dependency — read the OSV.dev advisory text (fetch https://api.osv.dev/v1/vulns/<id> if needed for details beyond the id) and cross-reference against the dependency's usedBy projects and, if helpful, a quick grep of how that package's APIs are actually called in those projects. Assign one of: reachable, not-reachable, unknown (use unknown rather than guessing when you genuinely can't tell).

Edge Case §1: if the component's shipsInRuntime is false (dev/build-tooling-only, from the inventory step), still report the match, but explicitly note it's a lower-relevance finding than a shipped runtime dependency — do not omit it.

5. Persist findings

.specify/scripts/bash/security-findings-store.sh \
  --findings-dir specs/008-adversarial-security-review/findings \
  start-run --capabilities dependency --scope full --trigger manual

Capture RUN_ID, then for each vulnerability match:

.specify/scripts/bash/security-findings-store.sh \
  --findings-dir specs/008-adversarial-security-review/findings \
  upsert-finding --run-id "$RUN_ID" --source dependency \
  --title "<OSV id + package name>" --description "<advisory summary + reachability rationale>" \
  --severity "<severity from the OSV match>" \
  --evidence "<package>@<version> (<OSV id>)" \
  --relevance "<reachable|not-reachable|unknown>"

6. Finalize and report

.specify/scripts/bash/security-findings-store.sh \
  --findings-dir specs/008-adversarial-security-review/findings \
  finalize-run --run-id "$RUN_ID" --full true

The dependency review always covers the full dependency set (there is no PR-style scoping for FR-003), so --full true is always correct here — a component upgraded to a patched version will correctly auto-resolve its prior finding (Acceptance Scenario 3, US2).

.specify/scripts/bash/security-report-render.sh \
  --findings-dir specs/008-adversarial-security-review/findings \
  --out specs/008-adversarial-security-review/findings/report.md

.specify/scripts/bash/security-report-render.sh \
  --findings-dir specs/008-adversarial-security-review/findings \
  --capability dependency --snapshot-date "$(date -u +%Y%m%d)" \
  --out "specs/008-adversarial-security-review/findings/$(date -u +%Y%m%d)-cve-review.md"

rm -f specs/008-adversarial-security-review/findings/.tmp-dependency-components.json \
      specs/008-adversarial-security-review/findings/.tmp-vulnerability-matches.json

The dated file is a git-tracked, point-in-time snapshot of just this capability's findings for today (re-running later the same day overwrites today's file, a new day gets a new file); report.md remains the always-current cross-capability view.

Show the user the ## Dependency/CVE Review section. Each finding must show its relevance — never present matches as an undifferentiated raw list (SC-005). If zero findings, say so explicitly.

7. Independence check (FR-010)

If asked to demonstrate FR-010, confirm this capability produces a complete, correct report using only findings.json/runs.json entries with source: dependency — no dependency on code or adversarial findings existing.

User Input

$ARGUMENTS