A command-line tool to convert CycloneDX (VEX/VDR/(S)BoM) Documents in JSON or XML format to PDF reports.
- Blazing Fast: Rust performance processes large BOMs in milliseconds with efficient concurrent processing
- Zero Dependencies: Single static binary with embedded fonts—no runtime dependencies, no package managers, no system libraries
- Minimal Footprint: ~10MB binary perfect for slim Docker images and resource-constrained environments
- True Parallelism: Thread-safe concurrent batch processing with configurable job limits
- Memory Safe: 100% safe Rust code (forbids unsafe)—no runtime crashes or memory issues
- Cross-Platform: Same binary works on Linux, Windows, macOS—compile once, run anywhere
- Air-Gap Friendly: Fully self-contained with embedded Liberation Sans fonts—works completely offline
Perfect for automated security reporting in containerized workflows, CI/CD pipelines, and production environments where reliability, speed, and minimal dependencies are critical.
- CycloneDX (VEX/VDR/(S)BoM) to PDF Converter
VEX2PDF is a Rust application that scans the current directory for CycloneDX (VEX/VDR/(S)BoM files (JSON and XML) and converts them to human-readable PDF reports. It fully supports the CycloneDX schema version 1.5 and provides compatibility for version 1.6 documents that only use 1.5 fields. Documents using 1.6-specific fields may not process correctly. The tool handles various elements of the CycloneDX document format including vulnerabilities, components, metadata, and more.
- Purpose: Communicates exploitability of vulnerabilities in specific contexts
- Focus: Real-world risk assessment and exploitability analysis
- Purpose: Provides comprehensive vulnerability assessments for components
- Focus: Known and unknown vulnerabilities with detailed analysis
- Features: Includes the "affected" property for component-vulnerability correlation
- Purpose: Inventories software components and dependencies
- Focus: Component listing and supply chain transparency
VEX2PDF renders CycloneDX vulnerability analysis information with visual enhancements to improve readability and quick risk assessment:
The tool displays vulnerability analysis states with color-coded formatting for immediate visual recognition:
- Exploitable (Red) - Vulnerability is directly or indirectly exploitable in the current environment
- In Triage (Orange) - Vulnerability is under active investigation by the security team
- Resolved (Green) - Vulnerability has been successfully remediated
- Resolved With Pedigree (Dark Green) - Remediated with verifiable commit history and audit trail
- Not Affected (Forest Green) - Component is confirmed not vulnerable to this issue
- False Positive (Steel Blue) - Incorrectly identified as vulnerable; not a real security issue
Response actions indicate what remediation steps are available or planned:
- Update (Blue) - Software update available to fix the vulnerability
- Rollback (Blue) - Rollback to a previous non-vulnerable version is the recommended action
- Workaround Available (Orange) - Temporary mitigation or configuration change exists
- Can Not Fix (Red) - Technical limitations prevent fixing this vulnerability
- Will Not Fix (Red) - Vulnerability will not be addressed (risk accepted or deprioritized)
When present in the CycloneDX document, the analysis section appears after each vulnerability's description and includes:
- State - Current vulnerability assessment status (color-coded)
- Response - Available or planned remediation actions (displayed as a bracketed list)
- Justification - Explanation for "Not Affected" determinations (e.g., "Code Not Reachable", "Protected By Compiler")
- Details - Comprehensive analysis text explaining the security team's assessment
- Timestamps - First issued and last updated dates for tracking analysis history
Analysis sections only appear when the CycloneDX document includes analysis data. If no analysis information exists for a vulnerability, the section is omitted entirely.
This tool uses Liberation Sans fonts to render PDFs. The fonts are embedded directly in the binary, so no extra font configuration is required and the binary works standalone and is fully portable.
The embedded Liberation Sans fonts are licensed under the SIL Open Font License (OFL).
Use the --license flag to display full license details:
vex2pdf --licenseThe font license file is also available at Liberation fonts License file in the current repository.
- Automatically scans directories for JSON and XML files with VEX/VDR/(S)BoM data
- Converts (VEX/VDR/(S)BoM) documents to structured PDF reports
- Supports both JSON and XML CycloneDX formats
- Preserves all key (VEX/VDR/(S)BoM) information including:
- Document metadata and timestamps
- Vulnerability details with severity ratings and sources
- New since v0.8.0 : Component-vulnerability correlation via "affected" property (VDR)
- Exploitability assessments and risk context (VEX)
- New: Vulnerability analysis with color-coded states and responses
- Analysis states: Exploitable (red), Resolved (green), In Triage (orange), False Positive (blue), Not Affected (green), Resolved With Pedigree (dark green)
- Response actions: Update/Rollback (blue), Workaround Available (orange), Can Not Fix/Will Not Fix (red)
- Justification explanations for not-affected vulnerabilities
- Detailed analysis text and timestamps (firstIssued, lastUpdated)
- Component inventories and dependencies (BOM/SBOM)
- Tools used to generate the CycloneDX (VEX/VDR/(S)BoM)) document
- Cross-platform support
- Rust and Cargo (latest stable version)
Install VEX2PDF directly from crates.io:
cargo install vex2pdfAfter installation, the vex2pdf binary will be available in your Cargo bin directory.
To use VEX2PDF as a library in your Rust project:
# Default: CLI + concurrent processing (recommended for most use cases)
cargo add vex2pdf
# Library with concurrent processing (no CLI dependencies)
cargo add vex2pdf --no-default-features --features concurrency
# Library with sequential processing (minimal dependencies)
cargo add vex2pdf --no-default-features
# CLI with sequential processing
cargo add vex2pdf --no-default-features --features cliFeature Flags:
| Feature | Description | Default |
|---|---|---|
cli |
Command-line interface and argument parsing (requires clap, env_logger) |
✓ Yes |
concurrency |
Concurrent file processing using threadpool (requires jlizard-simple-threadpool) |
✓ Yes |
Library Usage Example:
use vex2pdf::lib_utils::config::Config;
use vex2pdf::run;
fn main() {
let config = Config::default()
.working_path("./input")
.output_dir("./output")
.max_jobs(Some(4)); // Only available with 'concurrency' feature
run(config).expect("Failed to process files");
}For complete API documentation, visit docs.rs/vex2pdf.
Notice: As of v0.6.1 no extra font configuration is needed. Fonts have been embedded in the software binary. Check Fonts handling and license for further information
Clone the repository, then build the application with cargo build --release. The binary will be available at target/release/vex2pdf.
Users can either:
- Install via Cargo as described above
- Build from the source using for the respective platform and operating-system. Please check the From Source Section
- Use a pre-built binary under the Release Binaries section
Currently, No Mac Binaries are provided however Mac Users can build and install with cargo. Please check the From Source Section
If Mac release binaries are needed please create an issue
Version 2.0.0 introduces breaking changes to improve the library architecture and provide more flexibility. Most users won't need to make any changes.
No changes required! The CLI interface remains unchanged. All default features (CLI + concurrency) are enabled by default.
No changes required! Your code will continue to work as-is.
Version 2.0 introduces a new concurrency feature that's enabled by default. If you're using --no-default-features, you now have two options:
Option 1: Add concurrency back (recommended for most use cases)
# Update your Cargo.toml or installation command
cargo add vex2pdf --no-default-features --features concurrencyOption 2: Use sequential processing (simpler, no threading)
# No changes needed - files will now process sequentially
cargo add vex2pdf --no-default-featuresThe PdfGenerator struct no longer has a lifetime parameter:
Before (v1.x):
let generator: PdfGenerator<'_> = PdfGenerator::new(config);After (v2.0):
let generator: PdfGenerator = PdfGenerator::new(config);
// Or simply let type inference handle it:
let generator = PdfGenerator::new(config);If you were using these deprecated environment variables, switch to CLI flags:
| Removed Variable | Replacement |
|---|---|
VEX2PDF_SHOW_OSS_LICENSES=true |
vex2pdf --license |
VEX2PDF_VERSION_INFO=true |
vex2pdf --version |
- Concurrency is now optional: The
concurrencyfeature flag allows you to choose between concurrent (faster) or sequential (simpler) processing - External threadpool: Replaced internal implementation with
jlizard-simple-threadpoolfor better maintainability - Cleaner API: Removed deprecated fields from
PdfGeneratorstruct (deprecated since v0.9.0)
For a complete list of changes, see the CHANGELOG.md.
VEX2PDF is designed for batch processing and can be run without arguments to automatically process all CycloneDX files in the current directory. As of v0.9.0, the tool also supports command-line arguments for more precise control over input files, output directories, and report customization.
Run the application in a directory containing CycloneDX (VEX/VDR/(S)BoM files (JSON or XML):
./vex2pdfThe tool will:
- Scan the current directory for JSON and XML files
- Attempt to parse each file as a CycloneDX (VEX/VDR/(S)BoM) document
- Generate a PDF report with the same name as the original file (with .pdf extension)
- Display progress and results in the console
VEX2PDF supports command-line arguments for convenient configuration. All arguments can also be set via environment variables as shown in the Configuration section.
To see all available options, run:
vex2pdf --helpAvailable options:
A tool to convert CycloneDX(VEX) JSON or XML documents to PDF reports
Usage: vex2pdf [OPTIONS] [FILE_OR_FOLDER_TO_PROCESS]
Arguments:
[FILE_OR_FOLDER_TO_PROCESS] File to process (JSON or XML) or Folder containing said file types.
Please note that this tool is designed for batch processing. So If
this is not set the tool scans the current directory for all parseable
files and converts them. if a folder is set the tool scans just the
first level of the directory (non-recursive) [env: VEX2PDF_WORKING_PATH=]
Options:
-m, --show-novulns-msg <SHOW_NOVULNS_MSG>
[env: VEX2PDF_NOVULNS_MSG=] [possible values: true, false]
-t, --report-title <REPORT_TITLE>
Overrides the default title of the report [env: VEX2PDF_REPORT_TITLE=]
-n, --pdf-meta-name <PDF_META_TITLE>
Overrides the default PDF meta name [env: VEX2PDF_PDF_META_NAME=]
-b, --bom-novulns <PURE_BOM_NOVULNS>
Treats the file as a pure bill of materials and shows only the components
without the vulnerabilities [env: VEX2PDF_PURE_BOM_NOVULNS=] [possible values: true, false]
-c, --show-components <SHOW_COMPONENTS>
Controls whether the component list is shown [env: VEX2PDF_SHOW_COMPONENTS=]
[possible values: true, false]
-d, --output-dir <OUTPUT_DIR>
Sets the directory where the parser should output the files [env: VEX2PDF_OUTPUT_DIR=]
-j, --max-jobs <MAX_JOBS>
Sets the maximum number of jobs for concurrent generation tasks, when not set or set to `0`
this defaults to using the maximum available parallelism on the system which is given by
[`std::thread::available_parallelism`] [env: VEX2PDF_MAX_JOBS=]
-L, --license
Dumps the open-source software license text to the terminal and exits
-h, --help
Print help
-V, --version
Print version
Examples:
# Process a specific file
vex2pdf my-bom.json
# Process a specific directory
vex2pdf /path/to/bom/files/
# Specify output directory
vex2pdf my-bom.json -d /path/to/output/
# Hide components list
vex2pdf -c false
# Custom report title
vex2pdf -t "Security Vulnerability Assessment"
# Process with single-threaded mode (no concurrency)
vex2pdf --max-jobs 1 my-bom.json
# Process with 4 concurrent jobs
vex2pdf --max-jobs 4 /path/to/bom/files/
# Combine multiple options
vex2pdf my-bom.json -d ./reports/ -t "Q4 Security Report"$ ./vex2pdf
[2025-10-24T18:00:00Z INFO] vex2pdf 0.9.0 - CycloneDX (VEX) to PDF Converter
[2025-10-24T18:00:00Z INFO] Copyright (c) 2025 Salem B. - MIT Or Apache 2.0 License
[2025-10-24T18:00:00Z INFO]
[2025-10-24T18:00:00Z INFO] Active font path: <embedded liberationSans fonts> -- use --license to show Font license details
[2025-10-24T18:00:00Z INFO]
[2025-10-24T18:00:00Z INFO] Using default report title
[2025-10-24T18:00:00Z INFO] Using default pdf metadata title
[2025-10-24T18:00:00Z INFO]
[2025-10-24T18:00:00Z INFO] Scanning for BoM/Vex Files in ./documents
[2025-10-24T18:00:00Z INFO] Found 2 JSON files
[2025-10-24T18:00:00Z INFO] Found 5 XML files
[2025-10-24T18:00:00Z INFO] Processing ./documents/example1.json
[2025-10-24T18:00:00Z INFO] Generating PDF: ./documents/example1.json
[2025-10-24T18:00:00Z INFO] Successfully generated PDF: ./documents/example1.pdf
[2025-10-24T18:00:00Z INFO] Processing ./documents/example2.json
[2025-10-24T18:00:00Z INFO] Generating PDF: ./documents/example2.json
[2025-10-24T18:00:00Z INFO] Successfully generated PDF: ./documents/example2.pdf
[2025-10-24T18:00:00Z INFO] Processing ./documents/example3.xml
[2025-10-24T18:00:01Z WARN]
[2025-10-24T18:00:01Z WARN] NOTE: Downgrading CycloneDX BOM from spec version 1.6 to 1.5
[2025-10-24T18:00:01Z WARN] Reason: Current implementation does not yet fully support spec version 1.6
[2025-10-24T18:00:01Z WARN] Warning: This compatibility mode only works for BOMs that don't utilize 1.6-specific fields
[2025-10-24T18:00:01Z WARN] Processing will fail if 1.6-specific fields are encountered
[2025-10-24T18:00:01Z WARN]
[2025-10-24T18:00:01Z INFO] Generating PDF: ./documents/example3.xml
[2025-10-24T18:00:01Z INFO] Successfully generated PDF: ./documents/example3.pdf
[2025-10-24T18:00:01Z INFO] Processed 7 files
See sample generated PDFs from various CycloneDX documents in the repository:
- VDR with Vulnerability Analysis - Demonstrates color-coded analysis states (Exploitable, In Triage, Resolved) and response actions
- VDR with Multiple Vulnerabilities - Complex report showing multiple CVEs and affected components
- Simple VEX Report - Basic VEX document with single vulnerability
- XML-based VDR - Shows XML input processing
- VDR with GHSA Entries - GitHub Security Advisory integration example
All PDFs include embedded Liberation Sans fonts and require no additional dependencies to view.
No configuration files are required. However the application has some customization options available via Environment variables.
Windows Users: To set environment variables on Windows, use:
- Command Prompt:
set VEX2PDF_ENV_VARIABLE=false && vex2pdf- PowerShell:
$env:VEX2PDF_ENV_VARIABLE="false"; vex2pdf
The following environment variables can be used to customize behavior:
| Variable | Purpose | Default |
|---|---|---|
| VEX2PDF_NOVULNS_MSG | Controls the "No Vulnerabilities reported" message display | true |
| VEX2PDF_REPORT_TITLE | Overrides the default report title | Not set (uses default title) |
| VEX2PDF_PDF_META_NAME | Overrides the PDF metadata title | Not set (uses default metadata title) |
| VEX2PDF_PURE_BOM_NOVULNS | Whether to treat the file as a component list instead of a vulnerability list | false |
| VEX2PDF_SHOW_COMPONENTS | Whether to additionally show the component list after the vulnerability list | true |
| VEX2PDF_MAX_JOBS | Controls the maximum number of concurrent processing jobs | Not set (uses max parallelism) |
This variable controls how the Vulnerabilities section appears when no vulnerabilities exist:
- When set to "true" or not set (default): A "Vulnerabilities" section will be shown with a "No Vulnerabilities reported" message
- When set to "false": The Vulnerabilities section will be completely omitted from the PDF
Example : VEX2PDF_NOVULNS_MSG=false vex2pdf
Overrides the default report title with custom text
Example : VEX2PDF_REPORT_TITLE="My Custom VEX Report" vex2pdf
Overrides the PDF metadata title with custom text
Example 1 : VEX2PDF_PDF_META_NAME="VEX Report - Company XYZ" vex2pdf
Example 2 : VEX2PDF_PDF_META_NAME="VEX Report - Company XYZ" VEX2PDF_REPORT_TITLE="My Custom VEX Report" vex2pdf
Whether to treat the file as a pure CycloneDX Bill of Materials only listing the components and ignoring the vulnerability list
Example : VEX2PDF_PURE_BOM_NOVULNS=true vex2pdf
Whether to show the complete list of components after the vulnerabilities section. The default behaviour is true but this can be overridden
Example: VEX2PDF_SHOW_COMPONENTS=false vex2pdf
Controls the maximum number of concurrent jobs for processing multiple BOM files:
- When not set or set to
0(default): Uses all available CPU cores for maximum parallelism - When set to
1: Runs in single-threaded mode (sequential processing in main thread) - When set to
2-255: Uses the specified number of concurrent jobs
Single-threaded mode is useful for:
- Debugging and troubleshooting
- Systems with limited resources
- Reproducible processing order
Multi-threaded mode (default) provides:
- Faster processing of multiple files
- Better resource utilization on multi-core systems
Example (single-threaded): VEX2PDF_MAX_JOBS=1 vex2pdf
Example (4 concurrent jobs): VEX2PDF_MAX_JOBS=4 vex2pdf
Example (default parallelism): VEX2PDF_MAX_JOBS=0 vex2pdf or simply vex2pdf
VEX2PDF uses structured logging to provide clear visibility into its operation. Logs include timestamps, severity levels, and module paths for easy troubleshooting.
The tool supports four log levels:
- ERROR - Critical errors that prevent operation (output to stderr)
- WARN - Warnings about potential issues or compatibility concerns (output to stderr)
- INFO - Normal operational messages showing progress and results (output to stdout) - Default level
- DEBUG - Detailed internal information including worker thread activity (output to stdout)
By default, the tool shows INFO level logs without any configuration. You can control the log level using the RUST_LOG environment variable:
# Default behavior (info level) - no configuration needed
vex2pdf
# Show all logs including debug information (verbose mode)
RUST_LOG=debug vex2pdf
# Show only warnings and errors (quiet mode)
RUST_LOG=warn vex2pdf
# Show only errors (minimal output)
RUST_LOG=error vex2pdf
# Disable all logging
RUST_LOG=off vex2pdfNote: Debug logs are completely removed from release builds at compile time for optimal performance and smaller binary size.
Output Routing:
- Informational logs (INFO, DEBUG) → stdout - normal operational output
- Problem logs (WARN, ERROR) → stderr - errors and warnings for script handling
This separation allows for proper Unix-style piping and redirection:
# Capture only errors to a file
vex2pdf 2> errors.log
# Separate normal output and errors
vex2pdf > output.log 2> errors.logFor full API documentation, please visit:
To generate documentation locally:
cargo doc --openFor information about testing, code coverage, architecture, and the traits system, see Developer Notes.
The test suite includes comprehensive integration tests that validate PDF generation accuracy using BLAKE3 checksums of normalized content (with timestamps and dynamic IDs stripped).
# Run all tests (with CLI feature, default)
cargo test
# Run only library unit tests
cargo test --lib
# Run library tests without CLI dependencies
cargo test --lib --no-default-features
# Build library-only (no CLI dependencies)
cargo build --no-default-featuresNote: Integration tests require the cli feature and will be skipped when testing with --no-default-features.
Warning: PDF checksums used in integration tests are generated from debug builds. While checksums should be consistent across builds, differences in compiler optimizations between debug and release modes may occasionally cause checksum mismatches. If you encounter checksum failures in release builds, this is expected behavior and does not indicate a test failure.
# Install coverage tool
cargo install cargo-llvm-cov
# Generate HTML coverage report
cargo llvm-cov --html
# Opens coverage report in browser at target/llvm-cov/html/index.htmlTests work seamlessly from both the git repository and crates.io packages.
This tool fully supports CycloneDX schema version 1.5 and provides compatibility for version 1.6 documents that only use 1.5 fields. Documents using 1.6-specific fields may not process correctly. For more information about the CycloneDX format, see:
This tool implements a special compatibility mode for CycloneDX 1.6 documents:
- When the tool encounters a document with
specVersion: "1.6", it will:- Display a notification about downgrading to 1.5
- Automatically modify the document's spec version to "1.5"
- Attempt to process it using the 1.5 schema parser
This compatibility approach works well for documents that don't use 1.6-specific fields but allows the tool to process newer documents without requiring users to manually modify them.
Limitations:
- Documents that use 1.6-specific fields or structures may fail during processing
- No validation is performed for 1.6-specific features
- This is a temporary solution until full 1.6 support is implemented in the underlying cyclonedx-bom library
When processing 1.6 documents, you'll see console messages indicating the compatibility mode is active.
- The application reads and processes files from the current directory
- No network connections are established
- Input validation is performed on all JSON files
Changes to the software between version increments are documented under Changelog.md.
This project is licensed under either of:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you shall be dual-licensed as above, without any additional terms or conditions.
This project uses third-party dependencies that may be distributed under different licenses. Please refer to the license information provided with each dependency for details.
- CycloneDX for CycloneDX document specification
- cyclonedx-bom for CycloneDX parsing
- genpdf for PDF generation
- serde_json for JSON processing
- Liberation Fonts for the PDF rendering fonts