Related Fundamentals: VEX documents address vulnerabilities across all container layers; see Vulnerability Across All Layers and understand the supply chain context in Library CVE Maintainer Dependency.
The following diagram illustrates the VEX document lifecycle from vulnerability detection through justification:
graph TD A["Vulnerability<br/>Database"] -->|Scan| B["Container<br/>Image"] B -->|Find| C["CVE-2024-5678<br/>OpenSSL"] C -->|Analyze| D{Is Vulnerable<br/>Code<br/>Executed?} D -->|No:<br/>Code Not<br/>Present| E["Status:<br/>not_affected"] E -->|Justification| E1["vulnerable_code<br/>_not_present"] E1 -->|Evidence| E2["Static Analysis<br/>Binary Search<br/>Confidence: 98%"] D -->|No:<br/>Code Present<br/>But Not Called| F["Status:<br/>not_affected"] F -->|Justification| F1["vulnerable_code<br/>_not_in_execute_path"] F1 -->|Evidence| F2["Data Flow<br/>Analysis"] D -->|No:<br/>Configuration<br/>Mitigates| G["Status:<br/>not_affected"] G -->|Justification| G1["vulnerable_code<br/>_cannot_be_controlled<br/>_by_adversary"] G1 -->|Evidence| G2["Config Review<br/>Privilege Check"] D -->|Yes:<br/>Vulnerable| H["Status:<br/>affected"] H -->|Action| H1["Upgrade to<br/>Fixed Version"] H1 -->|Timeline| H2["Patch by<br/>Date X"] D -->|Maybe| I["Status:<br/>unknown"] I -->|Investigate| I1["Manual<br/>Review"] E -->|Create| J["VEX<br/>Document<br/>OpenVEX Format"] F -->|Create| J G -->|Create| J H -->|Create| J I -->|Create| J J -->|Filter| K["427 CVEs<br/>Detected"] K -->|After VEX<br/>Filtering| L["23 CVEs<br/>Actually Relevant"] L -->|Risk Based<br/>Triage| M["Focus on<br/>High Risk<br/>Vulnerabilities"] style E fill:#ccffcc style F fill:#ccffcc style G fill:#ccffcc style H fill:#ffcccc style J fill:#99ccff style M fill:#ffff99Creating VEX Documents to Suppress False-Positive CVEs
VEX (Vulnerability Exploitability Exchange) documents provide critical context for vulnerability assessment. Rather than treating all known vulnerabilities equally, VEX lets organizations communicate whether a vulnerability actually impacts their product based on component usage, configuration, and deployment environment.
CleanStart generates context-aware VEX documents automatically during image scanning and build verification, eliminating manual triage work and enabling faster security decisions.
Why VEX Matters
A container image scanning report listing 427 vulnerabilities is overwhelming. Of those, 387 may not affect your deployed application at all. Traditional vulnerability management treats them equally; VEX eliminates false positives through provable context.
Scenario: Your image contains OpenSSL with CVE-2024-5678 (critical in server contexts). Your container runs a stateless image processor that never opens network sockets. VEX status: not_affected (affected component not executed). You can skip remediation and focus on actual risks.
CleanStart VEX Generation
Automatic VEX Creation
CleanStart generates VEX documents for every scanning operation. The scanning engine analyzes the component inventory for every package in every layer, resolves transitive dependencies that are actually used, performs code flow analysis to determine whether vulnerable code paths are executed, reviews configuration impact to identify runtime settings that mitigate exploitability, and considers environment context including network exposure, privilege levels, and resource access.
VEX Document Structure
CleanStart VEX documents follow OpenVEX format:
{ "@context": "https://openvex.dev/ns/v0.2.0", "tooling": "CleanStart v2.0.0", "statements": [ { "vulnerability": { "name": "CVE-2024-5678", "aliases": ["GHSA-xxxx-yyyy-zzzz"] }, "timestamp": "2025-10-04T14:32:00Z", "products": [ { "identifier": "cleanstart-api:2.0.0", "identifiers": { "sbom": "sha256:abc123..." } } ], "status": "not_affected", "justification": "vulnerable_code_not_present", "impact_statement": "OpenSSL library included but vulnerable function __parse_cert_extensions() not called in binary.", "evidence": { "source": "static_analysis", "confidence": 0.98 } }, { "vulnerability": { "name": "CVE-2024-9999" }, "status": "affected", "products": [ { "identifier": "cleanstart-api:2.0.0" } ], "affected_range": "< 1.2.3", "fixed_range": ">= 1.2.3", "action_statement": "Upgrade PostgreSQL from 1.2.1 to 1.2.3" } ]}VEX Status Values
Status | Meaning | When to Use |
|---|---|---|
| Vulnerability does not impact product | Vulnerable package present but code path unreachable |
| Vulnerability impacts product | Code is executed and exploitable |
| Vulnerability fixed in newer version | Upgrade available and recommended |
| Status being determined | Pending deep code analysis results |
Justifications for "not_affected"
CleanStart VEX includes detailed justifications explaining why a vulnerability doesn't impact your build:
vulnerable_code_not_present → The vulnerable function is not called vulnerable_code_not_in_execute_path → Code exists but runtime conditions prevent execution vulnerable_code_in_deactivated_functionality → Feature containing vulnerability is disabled vulnerable_code_in_compile_time_feature_not_enabled → Optional feature not compiled in vulnerable_code_cannot_be_controlled_by_adversary → Input validation prevents exploit vulnerable_code_cannot_be_reached_by_user_supplied_input → Vulnerable code uses only internal data component_not_present → Dependency not actually included in image product_as_used_by_consumer_not_vulnerable → Consumer's usage pattern blocks exploitImage-Specific VEX Consumption
Vulnerability Triage with VEX
# Get VEX for scanned imagecleanimg-init --image myapp:1.0.0 --vex-output triage.vex # Filter to only "affected" statusjq '.statements[] | select(.status == "affected")' triage.vex # Display impact statementsjq '.statements[] | select(.status == "affected") | {cve: .vulnerability.name, action: .action_statement}' triage.vexOutput shows actionable items only—in this example, three CVEs requiring attention out of 427 total.
Integration with Scanning Tools
CleanStart VEX integrates with standard vulnerability scanners:
# Syft generates SBOM; CleanStart adds VEXsyft myapp:1.0.0 --output json > sbom.jsoncleanimg-init --sbom sbom.json --output-vex enriched.vex # Grype consumes VEX for enhanced reportinggrype myapp:1.0.0 --add-cpes-if-missingcat enriched.vex | grype --template json > final_report.jsonBuilding for VEX Compliance
Code Path Analysis
CleanStart uses static analysis and dynamic tracing to identify which vulnerable code is actually executed:
FROM alpine:3.19RUN apk add --no-cache openssl=3.1.4-r5COPY app /appCMD ["/app/process-files"]Analysis result: OpenSSL CVE-2024-5678 (certificate parsing) → not_affected (no TLS in process-files). OpenSSL CVE-2024-9012 (encryption) → affected (AES-256 used in file processing).
Minimal Base Images Reduce VEX Burden
Using distroless or minimal images automatically improves VEX status:
# Before: Debian baseFROM debian:bookwormRUN apt-get install -y curl wget git openssh-client vimCOPY app /app# VEX: 200+ packages included, many unused → high vulnerability burden # After: Alpine or distrolessFROM gcr.io/distroless/base-debian12COPY --from=builder /app /app# VEX: 12 packages total, all required → cleaner VEX reportVEX for Compliance Reporting
FedRAMP Vulnerability Assessment
VEX documents satisfy FedRAMP requirements by providing evidence of vulnerability assessment and risk acceptance decisions:
{ "vulnerability": { "name": "CVE-2024-2222" }, "status": "not_affected", "justification": "vulnerable_code_cannot_be_controlled_by_adversary", "impact_statement": "Remote code execution requires administrator privileges; application runs as unprivileged user with no privilege escalation vectors.", "evidence": { "source": "runtime_monitoring", "confidence": 0.95, "timestamp": "2025-10-04T16:45:00Z" }, "compliance_note": "Assessed against FedRAMP IA-4 (Access Control) and SI-2 (Flaw Remediation)"}EU CRA Vulnerability Documentation
CleanStart VEX satisfies EU Cyber Resilience Act requirements to document known vulnerability status:
cleanimg-init --compliance eu-cra --output-vex cra-compliance.vex# Includes:# - Vulnerability severity and CVSS score# - Impact statement for non-technical stakeholders# - Remediation timeline and status# - Evidence of vulnerability assessmentAdvanced VEX Features
Transitive Dependency Analysis
VEX doesn't just analyze direct dependencies:
{ "vulnerability": { "name": "CVE-2024-3333" }, "products": [ { "identifier": "myapp:1.0.0", "dependency_chain": [ "myapp → api-client v2.1.0", "api-client → http-library v5.0.0", "http-library → openssl v3.1.4" ] } ], "status": "not_affected", "justification": "vulnerable_code_not_in_execute_path", "impact_statement": "Vulnerable OpenSSL function only called by TLS 1.0 cipher negotiation. Application enforces TLS 1.3 minimum."}Time-Sensitive VEX
VEX statements include temporal context for change management:
{ "vulnerability": { "name": "CVE-2024-4444" }, "status": "affected", "action_statement": "Upgrade required by 2025-12-15 (90 days from disclosure)", "deployment_windows": [ { "environment": "staging", "deadline": "2025-11-15" }, { "environment": "production", "deadline": "2025-12-15" } ]}VEX Best Practices
Generate VEX for Every Build
Make VEX generation part of your CI/CD pipeline:
scan: stage: verify script: - cleanimg-init --scan --output-vex vex-report.json - cleanimg-init --vex vex-report.json --validate-compliance fips,feds artifacts: paths: - vex-report.jsonPublish VEX Alongside Artifacts
Include VEX with container image metadata:
# Store VEX with imagecosign attach attestation myapp:1.0.0 --attestation vex-report.json --type vex # Retrieve VEX during deploymentcosign verify-attestation myapp:1.0.0 --type vex | jq .Review VEX for "affected" Status Only
Establish clear processes for remediating VEX "affected" vulnerabilities:
# Extract action itemscat vex-report.json | jq ' .statements[] | select(.status == "affected") | { cve: .vulnerability.name, severity: .severity, action: .action_statement, deadline: .deployment_windows[0].deadline }' | sort_by(.deadline)Troubleshooting VEX Generation
Missing Vulnerability Context
If VEX shows "under_investigation" for many vulnerabilities:
# Run with increased analysis depthcleanimg-init --scan --analysis-depth=deep --output-vex report.vex # Enable dynamic tracingcleanimg-init --scan --trace-runtime --output-vex report.vexConfidence Scores Below Threshold
VEX confidence below 0.85 indicates uncertain analysis:
# Filter low-confidence statementscat report.vex | jq '.statements[] | select(.evidence.confidence < 0.85)' # Manual review required for security decisionsSee Also
SBOM Integration: spdx-sbom.md — VEX pairs with SBOM for complete vulnerability context. Image Signing: image-signing-sigstore.md — Sign VEX documents for authenticity. Compliance Reporting: fedramp-high.md — Using VEX for regulatory compliance.
