CVE Inventory Digest: Known-At-Sign-Time vs Disclosed-Later
Asqav binds the producer's CVE inventory snapshot into the signed receipt via cve_inventory_digest, a SHA-256 over the canonical-JSON list of CVE records the client held at the moment of signing. The field lets an auditor distinguish "the producer knew about this CVE and signed anyway" from "this CVE was disclosed after the action was signed".
What is the cve_inventory_digest field?
cve_inventory_digest is an OPTIONAL string on POST /api/v1/agents/{id}/sign. The wire format is sha256:<64 lowercase hex>. The value is the digest of the JSON list of CVE records the producer's vulnerability scanner returned at sign-time.
The digest accepts any JSON-serialisable list of CVE records (the shape produced by pip-audit, osv-scanner, trivy fs, grype, or an equivalent): it is the SHA-256 of the JCS (RFC 8785) canonical bytes of the list, computed with asqav.canonicalize as shown below.
How does Asqav address vulnerability tracking?
The NSA CSI describes the vulnerability inventory requirement in the recommendations chapter:
Internally, an organization should maintain a clear inventory of all deployed MCP agents and tools, along with versioning, patch history, and known security concerns. Externally, the organization should also monitor public vulnerability disclosure platforms (e.g., National Vulnerability Database (NVD), the Github MCP Server Vulnerabilities, etc.), to verify that no compromised servers, integrations, configurations, etc. are running in the environment. NSA CSI U/OO/6030316-26, p.13
Asqav binds the inventory snapshot into the signed receipt itself. The producer's scanner output at the moment of signing is hashed and the digest lives in the signed envelope. Six months later, when a new CVE is disclosed that affects a dependency the agent was running, an auditor can:
- Recover the digest from the receipt.
- Recover the inventory the producer used at sign-time (kept by the producer alongside its scan history).
- Confirm the disclosed CVE was NOT in the inventory at sign-time.
- Treat the receipt as "signed in good faith against the then-known vulnerability surface".
The reverse case is also detectable: a CVE that WAS in the inventory at sign-time and the producer signed anyway is a deliberate accept-known-risk event, which a compliance workflow can flag.
How do I produce a CVE-bound receipt?
The inventory snapshot is whatever the producer's scanner returned. The Asqav recommendation is to refresh the snapshot at a cadence (e.g. once per process restart, or once per hour for long-lived processes) and pass the digest of the most recent snapshot on every sign call.
JSON wire example
{
"action_type": "mcp:tool_call",
"cve_inventory_digest": "sha256:9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca7"
}
Python SDK
import asqav
import hashlib
import subprocess
import json
asqav.init()
agent = asqav.Agent.create("ci-runner")
scan = subprocess.run(
["pip-audit", "--format", "json"], capture_output=True, text=True, check=False
)
inventory = json.loads(scan.stdout)
# JCS (RFC 8785) canonical bytes of the CVE list, hashed with SHA-256
digest = "sha256:" + hashlib.sha256(
asqav.canonicalize(inventory["dependencies"])
).hexdigest()
receipt = agent.sign(
"mcp:tool_call",
{"tool": "deploy.run", "build_id": "b-12345"},
cve_inventory_digest=digest,
)
Generating an inventory
Any of the standard ecosystem scanners produces a JSON inventory the SDK helper accepts:
pip-audit (Python)
pip-audit --format json > cve-inventory.json
osv-scanner (multi-language)
osv-scanner --format json --recursive . > cve-inventory.json
trivy (container plus filesystem)
trivy fs --format json --quiet . > cve-inventory.json
grype (multi-language)
grype dir:. -o json > cve-inventory.json
curl
curl -X POST https://api.asqav.com/api/v1/agents/agt_ci_001/sign \
-H "X-API-Key: $ASQAV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action_type": "mcp:tool_call",
"cve_inventory_digest": "sha256:9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca7"
}'
How does an auditor use the digest?
The auditor holds the receipt (with the digest) and the producer's archived inventory snapshots (kept by the producer's scanner pipeline). To reconstruct the known-at-sign-time vulnerability surface, the auditor:
- Reads
cve_inventory_digestfrom the signed envelope. - Pulls the matching inventory snapshot from the producer's archive (the producer keeps inventory snapshots indexed by digest).
- Rehashes the snapshot (SHA-256 over
asqav.canonicalizeof the list) and confirms the value matches. - Cross-references each CVE in the snapshot against the disclosed-vulnerability timeline.
A CVE present in the snapshot at sign-time and never patched is a "knew about it" event. A CVE absent from the snapshot at sign-time and disclosed publicly later is a "could not have known" event. The receipt does not need to be re-signed for the second case to be defensible.
What does the inventory NOT cover?
Three classes of risk are not addressed by cve_inventory_digest.
Zero-days
A CVE not yet disclosed at sign-time will not be in any scanner's output. The digest binds what was knowable. It does not bind what was true.
Scanner gaps
A scanner that misses a vulnerability misses it. The digest only proves the scanner's output, not the absence of vulnerabilities globally.
Transitive code paths
A CVE in a dependency the agent never actually reached at runtime is still in the inventory. The digest does not prove exploitability, only presence in the dependency graph.