Add vulnerability context without building an intel pipeline
Most vulnerability scanners output CVSS scores and CVE IDs. They cannot tell you what is being actively exploited right now. Adding that context normally requires a full threat intelligence team. attestd is the API shortcut.
Scanner output without exploitation context creates backlog, not action. Teams sort by CVSS and still miss what is being used in the wild.
- →CVSS measures severity of a vulnerability class, not whether anyone is exploiting this product@version today.
- →Building a KEV + EPSS + registry monitoring pipeline is real engineering work. Most tool vendors should not own that stack.
- →Supply chain compromises often score clean on CVE checks. Enrichment that only joins CVE IDs misses the compromise signal.
- →Enterprise exploit feeds are priced and gated for large buyers. A self-serve API call is the shortcut for product teams shipping a scanner.
Join these fields onto each finding. Keep your CVSS. Add the decision layer your users actually need.
| Field | Meaning for this use case |
|---|---|
actively_exploited | Promote the finding to P0 / urgent when true. This is the enrichment most scanners lack. |
risk_state | Attestd's categorical severity for the product@version. Use for sort order alongside or instead of raw CVSS. |
remote_exploitable | Network-reachable conditions deserve higher priority than local-only findings with the same CVSS. |
supply_chain.compromised | Surface as a separate finding type. Confirmed malicious package, not a CVE. |
patch_available / fixed_version | Give users an upgrade target in the same enrichment payload, not a second lookup. |
curl "https://api.attestd.io/v1/check?product=log4j&version=2.14.1" \
-H "Authorization: Bearer $ATTESTD_API_KEY"import os
import attestd
client = attestd.Client(api_key=os.environ["ATTESTD_API_KEY"])
def enrich_finding(product: str, version: str, cve_id: str) -> dict:
"""Enrich a scanner finding with real-world exploitation data."""
risk = client.check(product, version)
compromised = bool(risk.supply_chain and risk.supply_chain.compromised)
priority = "P0" if (
risk.risk_state == "critical"
or risk.actively_exploited
or compromised
) else "P2"
return {
"cve": cve_id,
"product": product,
"version": version,
"cvss_score": get_cvss(cve_id), # your existing data
"actively_exploited": risk.actively_exploited,
"remote_exploitable": risk.remote_exploitable,
"patch_available": risk.patch_available,
"fixed_version": risk.fixed_version,
"supply_chain_compromised": compromised,
"attestd_risk_state": risk.risk_state, # enriched signal
"priority": priority,
}- 01
Resolve product and version per finding
Map your scanner's package or CPE identity to an Attestd product slug and version string. Call /v1/check once per unique pair.
- 02
Join enrichment onto the finding
Attach actively_exploited, risk_state, supply_chain.compromised, and fixed_version to the finding object your UI or ticket system already uses.
- 03
Reprioritize the queue
Sort or filter so actively exploited and compromised findings float above CVSS-only noise. Keep CVSS for users who still want it.
Findings are prioritized by what is actually being exploited.
Instead of presenting a list of hundreds of CVSS scores, your tool can surface a short list of things that matter right now. Vulnerabilities with confirmed active exploitation, plus confirmed supply chain compromises. No threat intel team required.
The detection track record is the product argument. Attestd flagged VS Code Fake Font five days before JFrog's disclosure, TanStack and Mistral roughly two and a half hours before BleepingComputer despite valid SLSA Build Level 3 attestations and a passing npm audit, and the AsyncAPI re-compromise via live monitoring rather than a lookup against the original advisory.
Full timestamps live in the detection ledger. For signal-quality and access-model comparisons, see Attestd vs VulnCheck, Attestd vs NVD, and Attestd vs Snyk.