Local findings format¶
A local findings file supplies vulnerability and exploitability data without a network provider. The file must resolve to a regular file and contain no more than 5 MiB of UTF-8 JSON. A symbolic link to a regular file is accepted. FIFOs, devices, sockets, directories, and links to those objects are rejected before content is read.
The top-level value is an object with one required findings array. Unknown fields and duplicate object keys at any depth are rejected. JSON may contain at most 100 nested arrays or objects, and an integer literal may contain at most 1,000 decimal digits. The array may contain at most 10,000 items.
{
"findings": [
{
"id": "CVE-2026-0001",
"component_ref": "component:django",
"source_name": "Internal Review",
"source_url": "https://security.example.test/vulns/CVE-2026-0001",
"modified": "2026-01-01T00:00:00Z",
"analysis_state": "not_affected",
"analysis_detail": "The affected feature is disabled in this deployment.",
"impact_statement": "The deployment does not enable the affected feature."
}
]
}
Top-level field¶
Field |
Required |
Type |
Description |
|---|---|---|---|
|
Yes |
Array |
Zero to 10,000 finding objects. CycloneDX accepts an empty array, but OpenVEX, CSAF, and SPDX 3 output reject it. |
Finding fields¶
Field |
Required |
Default |
Rules |
|---|---|---|---|
|
Yes |
— |
Non-empty vulnerability identifier. |
|
One selector required |
— |
Non-empty component reference from the parsed SBOM. |
|
One selector required |
— |
Valid package URL that matches exactly one parsed component. |
|
No |
|
Non-empty string. |
|
No |
|
HTTP or HTTPS URL with a host and no username or password. CSAF output also requires ASCII RFC 3986 syntax. |
|
No |
Omitted |
ISO-8601 timestamp string. Naive values are treated as UTC. |
|
No |
|
One of the states listed below. |
|
No |
|
Non-empty human-readable analysis. |
|
No |
Omitted |
Non-empty remediation or mitigation text. OpenVEX, CSAF, and SPDX 3 require it for |
|
No |
Omitted |
Non-empty impact text. OpenVEX, CSAF, and SPDX 3 require it for |
|
No |
Omitted |
Non-empty version text. OpenVEX, CSAF, and SPDX 3 require it for |
|
No |
Omitted |
One of the remediation categories listed below. CSAF requires it for |
Supported analysis_state values are resolved, exploitable, in_triage, false_positive, and not_affected.
Supported remediation_category values are mitigation, no_fix_planned, none_available, vendor_fix, and workaround.
Do not put credentials or secrets in source_url, including its query string. Vexcalibur rejects URL userinfo such as user:password@host. Query values may be serialized into every generated VEX format, so use an attributable public advisory URL rather than a signed or credential-bearing link.
CycloneDX output ignores action_statement, impact_statement, fixed_version, and remediation_category. These fields do not change CycloneDX grouping, content, or document identity.
OpenVEX ignores remediation_category. It does not change OpenVEX grouping,
content, or document identity. CSAF emits the category with a product-scoped
remediation and will not infer one from action_statement or
analysis_detail.
OpenVEX and SPDX 3 reject nonidentical assertions for the same vulnerability ID and emitted product package URL. Differences in source, state, analysis detail, action statement, impact statement, fixed version, or modification time make assertions nonidentical for both; SPDX 3 also distinguishes remediation categories. CSAF groups provenance and evidence when the effective product status agrees, including multiple action or impact objects, but rejects contradictory effective statuses for the pair.
modified describes the source record. CycloneDX maps it to vulnerability
updated; OpenVEX keeps it in status_notes. CSAF keeps it in vulnerability
notes. SPDX 3 keeps it in status notes and emits a vulnerability
modifiedTime only when the findings for that vulnerability report exactly
one distinct time. No output treats it as a document or statement revision
time.
OpenVEX, CSAF, and SPDX 3 require a version in the emitted product package URL. They use the component’s separate version when the package URL is unversioned and reject the assertion when both are unversioned.
CSAF maps false_positive and not_affected to the same
known_not_affected product status. It preserves the original state in notes
so consumers can see the lossy mapping. Read the CSAF output
contract for all state and evidence mappings.
Component matching¶
At least one of component_ref and purl is required.
For local CycloneDX input, component_ref is the component’s bom-ref. For GitHub SPDX input, it is the package SPDXID when present and otherwise the package URL.
For local SPDX 3 input, component_ref is the package’s nonblank spdxId
with outer whitespace removed. A missing or blank spdxId falls back to the
canonical package URL.
When both selectors appear, they must identify the same component. A package URL that appears under more than one component reference is ambiguous and rejected; use component_ref in that case.