CVE Intelligence Intake
SecurityRecipes treats CVE intelligence as an intake problem before it treats it as a patching problem. A scanner finding, GHSA entry, NVD row, vendor bulletin, or ticket is a signal. It becomes an agent task only after the signal has enough evidence for a reviewer to trust the resulting PR.
The intake gate is intentionally conservative:
- no primary source, no remediation task;
- no affected surface, no remediation task;
- no fix, mitigation, containment, or suppression path, no remediation task;
- no reviewer-runnable verification, no remediation task.
Artifacts
- Prompt: CVE intelligence intake gate
- Policy:
data/intelligence/cve-intelligence-intake-gates.json - Regression fixtures:
data/intelligence/cve-intelligence-intake-fixtures.json - Evaluator:
scripts/evaluate_cve_intelligence_intake.py - Fixture runner:
scripts/test_cve_intelligence_intake_decisions.py - CVE recipe hub: CVE Recipes
- Generic dependency workflow: Vulnerable Dependency Remediation
Decision Model
The policy defines five outcomes:
| Decision | Use when | Output |
|---|---|---|
| Accept for remediation | A stable ID, affected surface, fix path, ownership, and verification all exist. | Remediation packet and selected recipe. |
| Accept for containment | Exposure is plausible or confirmed, but full remediation is blocked. | Temporary control and follow-up record. |
| Suppress as not exposed | The vulnerable component is absent, unreachable, dev-only, test-only, or below exploit preconditions. | Evidence-backed suppression with expiration. |
| Stop for triage | Sources disagree, evidence is missing, ownership is unclear, or safe verification is impossible. | TRIAGE.md. |
| Reject unverified signal | The claim has no stable primary source or affected surface. | REJECTED_SIGNAL.md. |
Source Order
Use the strongest available source for the decision being made:
- Vendor advisory, release note, patch commit, or security bulletin.
- GitHub Advisory Database.
- CVE record or NVD entry.
- OSV, package-registry advisory, or ecosystem feed.
- CISA KEV, vendor exploitation notice, incident signal, or trusted threat intelligence feed.
Scanner output is valuable repository evidence, but it should not be the only source for a patch decision. It usually tells the team that a package or image may be present. It rarely proves reachability, safe fixed versions, operational side effects, or whether a mitigation is acceptable.
Known-exploited and threat-intelligence feeds raise priority, but they are not standalone remediation sources. Pair them with a vendor advisory or patch, GitHub Advisory Database entry, CVE/NVD record, OSV entry, or package-registry advisory before accepting remediation, containment, or suppression.
For deterministic checks, a primary-source type is not enough by itself. The
packet must include an absolute http or https source URL, or the evaluator
routes the signal to triage. The reverse is also true: a
primary_source_backed: true flag cannot promote a scanner, ticket,
social-media, unknown-source URL, or KEV-only exploitation signal into primary
evidence. Remediation, containment, and suppression packets also need a named
owner. Containment and suppression packets additionally need a parseable
YYYY-MM-DD follow-up date that is not earlier than the packet’s
evaluation_date, so temporary decisions do not become permanent or start
already overdue. Containment must still name the exact control or
configuration change; temporary_control: true is not an actionable path by
itself.
The evaluator also returns a source_evidence audit block. It lists the source
types that can stand alone, the links that counted as valid primary sources,
and the links that were preserved only as auxiliary, invalid, or
non-standalone evidence. That distinction matters when a KEV or threat
intelligence link raises priority but must still be paired with a vendor,
GHSA, CVE/NVD, OSV, or package-registry source before remediation starts.
Operating Loop
- Start with one advisory signal and one repository or service scope.
- Run the intake prompt and require one of the five output files.
- If the decision is remediation, hand the packet to the most specific
SecurityRecipes prompt:
- a named CVE recipe when one exists;
- vulnerable-dependency remediation for routine package CVEs;
- base-image remediation for OS-package or container-layer CVEs;
- artifact quarantine for malicious package compromise.
- If the decision is containment, keep the containment small and record the owner, expiration, and follow-up patch path.
- If the decision is suppression, bind it to evidence and an expiration date.
- If the decision is triage or rejection, do not ask an agent to patch.
Evaluate a Packet
The intake gate has a deterministic evaluator for local smoke checks and CI. Use it after a model or analyst drafts a packet, before a remediation prompt is run.
python3 scripts/evaluate_cve_intelligence_intake.py \
--packet path/to/intake-packet.json
The evaluator can also read a JSON packet with --packet. The packet should
use the review fields from the policy: canonical_id, aliases,
source_links, affected_surface, affected_range, repository_evidence,
fix_or_containment_path, verification_commands, selected_recipe, owner,
evaluation_date, and follow_up_date.
Each primary source in source_links should include both source_type and
url. Source types are normalized case-insensitively, but packets should still
use the policy values so reviewers can compare them directly.
The JSON output includes valid_primary_source_count and
invalid_or_non_standalone_source_count so CI logs can show why a packet was
accepted or routed to triage without requiring a reviewer to diff the full
normalized output.
Stable identifiers include CVE, GHSA, OSV-family and ecosystem advisory IDs
such as PYSEC, RUSTSEC, GO, USN, RHSA, ALAS, and VMSA. The
canonical_id must match a supported identifier format exactly; a valid alias
does not rescue a malformed canonical ID. A value that only starts with a valid
CVE or GHSA prefix is routed to triage until the canonical ID is cleaned up.
Continuation dates use YYYY-MM-DD; follow_up_date cannot be earlier than
the packet’s evaluation_date.
Regression Fixtures
The fixture file contains packets for each supported routing outcome plus evidence-quality regressions: remediation, ecosystem advisory remediation, ownerless remediation, containment, not-exposed suppression, mixed vendor-plus-KEV source auditing, missing or non-URL source links, incomplete containment evidence, scanner links that claim primary-source backing, KEV-only exploitation signals, temporary-control claims without an actionable path, malformed canonical identifiers, malformed follow-up dates, human triage, stale follow-up dates, and rejected unverified signal. Run the full regression set with:
python3 scripts/test_cve_intelligence_intake_decisions.py
Run one case when changing evaluator logic:
python3 scripts/test_cve_intelligence_intake_decisions.py \
--case triage_on_source_disagreement
Add a fixture whenever a new rule changes routing behavior. The evaluator is small by design, so examples are the clearest contract for reviewers and future automation runs.
What Reviewers Should Demand
A reviewer should reject a CVE remediation PR that cannot answer:
- Which primary sources were used?
- Which exact package, image, framework, route, plugin, runtime, or product component is affected?
- Which resolved version, commit, image digest, configuration, or runtime path proves exposure?
- What is the selected fixed version, fixed commit, mitigation, containment, or suppression path?
- Which command or probe proves the risk is gone or not exposed?
- What changed beyond the target advisory?
June 2026 Iteration
This iteration adds the intake gate because the CVE recipe catalog has grown large enough that “find a named recipe and patch” is no longer the whole workflow. New advisories need a front door that separates actionable remediation from unverified signals, no-fix advisories, not-exposed findings, and source disagreements.
That keeps the CVE catalog focused on reviewer-ready recipes instead of turning it into a vulnerability database.