ai-discovered-vulns-runner

Status: Local-only operator tool — not a scheduled task Source: the VDB itself (Kev, Exploit/ExploitCVE, EpssScore) joined against a hard-coded vulnerability list Type: n/a — no upstream feed Source slug: none — writes no CVEMetadata Schedule: none. No ECS task definition, no EventBridge schedule, no Containerfile target, no justfile recipe. Invoked by hand.

Overview

summary-processor owns the ai_discovered_vulns_outcomes SummaryLog row — the per-vulnerability “what happened next” panel served by GET /v2/ai-discovered-vulns-outcomes and rendered by website/src/pages/articles/ai-discovered-vulnerabilities.vue. That row is produced once a day alongside every other summary stat.

This binary exists so an operator can recompute only that row after editing the article’s vulnerability list, instead of triggering a full summary run:

set -a && source .env.production && set +a
go run ./cmd/ai-discovered-vulns-runner -force

For each tracked identifier it reads current exploit intelligence out of the VDB and emits one JSON payload:

  • KEV status — every Kev row for the id, the set of KEV sources, and the earliest dateAdded (main.go:281).
  • Exploit availability — total ExploitCVE count, whether any linked Exploit is weaponised, and first-seen timestamps for both (main.go:311). “Weaponised” is keyed on Exploit.source, not Exploit.category: category is mostly NULL (nuclei, metasploit, github-poc, packetstorm and vulnerability-lab write none) and leaks Snort classtypes and ExploitDB free text. The source list mirrors vdb-api’s exploitSourceMaturity weaponized set so both services agree on the word.
  • EPSS — newest EpssScore row per id by dateString (main.go:339).

Aggregates (totals, autonomous vs human-assisted, by AI system / org / affected vendor / severity, average EPSS) are folded in alongside the per-entry outcomes.

Records produced

ConditionRecords
Every runone SummaryLog row — label = "ai_discovered_vulns_outcomes", value = number of tracked entries, expr = "json", metadata = the outcomes + aggregate payload, timestamp = time.Now().UnixMilli()

Nothing else is written. All reads go to the read pool; the single write goes to the write pool (main.go:252).

The vulnerability list is duplicated — and drifts

The tracked identifiers live in a hard-coded aiDiscoveredVulnIds slice in two places:

CopyRole
cmd/summary-processor/ai_discovered_vulns.gocanonical — what the daily run and therefore the live article use
cmd/ai-discovered-vulns-runner/main.gocopy, meant to be kept in sync by hand

They are not in sync, and there is no test that they are. Because the API reads the most recent SummaryLog row for the label, running this binary while its copy is behind replaces a fuller payload with a smaller one — the article silently loses entries until the next daily summary-processor run restores them.

Before running it, diff the two slices. Prefer running summary-processor scoped to the single stat if that is available.

Failure modes

SituationBehaviour
DATABASE_URL unsetlog + os.Exit(1)
KEV query failsos.Exit(1) — the stat is not written
Exploit or EPSS query failslogged as a warning; the payload is still written with those fields absent
Write failsos.Exit(1)

The whole run is bounded by a 10-minute context and the compute phase by a further 5 minutes (main.go:236, main.go:260). Unlike the scheduled processors it takes no EXPECTED_DURATION_MINUTES into account, and it does not ON CONFLICT on (label, timestamp) the way summary-processor does.

Flags

-force is accepted for symmetry with the processor recipes; the runner always recomputes and always writes.

Key files

FilePurpose
scripts/go-processors/cmd/ai-discovered-vulns-runner/main.gowhole binary — list, queries, payload, write
scripts/go-processors/cmd/summary-processor/ai_discovered_vulns.gocanonical implementation and canonical list
website/src/pages/articles/ai-discovered-vulnerabilities.vueconsumer of the published payload

S3 Persistence

Not used. This processor does not currently archive payloads or quarantine failures to S3. Per the S3 Persistence Contract this is non-compliant — see the compliance matrix for the implementation roadmap.

Expected paths when implemented:

  • Archive: ai-discovered-vulns-runner/files/{sha256}/{filename}
  • Quarantine: failed-feeds/ai-discovered-vulns-runner/{YYYY-MM-DD}/{reason}/{filename}
  • Likely reasons: (none documented)