Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SecPod VEX Studio

Guided VEX authoring for OSS maintainers — from zero to a published VEX document in one command.

License Python OpenVEX VEX Hub


Why This Exists

If you maintain an open source package, you already know the problem:

Your users run trivy image or grype and get a wall of CVE alerts — many in libraries your package bundles as transitive dependencies, in code paths your package never actually calls. They open issues on your repo asking why you haven't patched it. You know it's not exploitable in your context, but you have no formal way to say so.

VEX (Vulnerability Exploitability eXchange) is the standard that lets you do exactly that. A VEX document is a machine-readable statement like "CVE-2021-45046 does not affect this package because the vulnerable JNDI code path is never reached through our public API." Once published, Trivy and Grype automatically suppress those alerts for every downstream user of your package.

The barrier: existing tools assume you already know the answer

Tools like vexctl and lib4vex are format generators — they take your not_affected decision and write it as OpenVEX/CSAF JSON. That's useful, but it skips the hard part: how do you know if a CVE is exploitable in your code? Security analysis is not most maintainers' day job.

The OASIS December 2025 industry report confirmed this: most maintainers give up at step 1 or step 5 of a 10-step manual VEX authoring process. Not because they don't care — because the tooling assumes expert security knowledge they don't have.

The solution: embed the expertise in the tool

VEX Studio is the "TurboTax for VEX". TurboTax doesn't expect you to know tax law — it asks you questions and derives the right answer. VEX Studio does the same for exploitability:

  • CWE-guided questionnaires — For each CVE, the tool looks up its CWE type and asks 2–4 targeted questions. CWE-502 (Deserialization)? "Does your package call the affected deserialization functions with untrusted data?" CWE-79 (XSS)? "Does your package render user-supplied input from this library in a browser?"
  • Structured determination — Your Yes/No answers map to the correct VEX status and justification code, with no ambiguity.
  • Named, auditable output — The VEX document is named after the package (e.g. express-4.18.2.openvex.json), timestamped, and includes the full decision audit trail.

Urgency: the EU Cyber Resilience Act

The EU CRA's vulnerability reporting requirements take effect September 11, 2026. Every software company selling into Europe must formally track and communicate vulnerability exploitability status. VEX is the mechanism. VEX Studio is the fastest path to compliance for OSS maintainers.


Quick Start

Prerequisites

Install

git clone https://github.com/secpod/vex-studio.git
cd secpod-vex-studio

python -m venv .venv
source .venv/bin/activate        # macOS / Linux
.venv\Scripts\activate           # Windows

pip install -e .

Your first VEX document (one command)

# Assess a package by PURL — generates SBOM, scans CVEs, guides triage, publishes VEX
vex-studio assess -p pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1

# Python package
vex-studio assess -p pkg:pypi/django@3.2.0

# Node.js package
vex-studio assess -p pkg:npm/express@4.18.2

# Your current Python project
vex-studio assess requirements.txt

The tool walks you through triage for each CVE found and writes a VEX document named after the package — e.g. log4j-core-2.14.1.openvex.json — ready for submission to Aqua VEX Hub.


How It Works

The assess command runs a guided 4-step workflow:

Step 1: Generate SBOM   Builds a CycloneDX SBOM from your package PURL or project files
         |
Step 2: Scan CVEs       Queries OSV.dev + GitHub Security Advisories for all known CVEs
         |
Step 3: Triage          For each CVE, asks CWE-specific exploitability questions:
         |                CWE-502?  "Does your package call the affected deserialization functions?"
         |                CWE-79?   "Does your package render user input from this library in a browser?"
         |                ...guided to a status: not_affected | affected | fixed | under_investigation
         |
Step 4: Publish VEX     Writes a valid OpenVEX 0.2.0 document named after the package

Each decision is saved as it's made — Ctrl+C never loses progress. Resume with vex-studio triage.

CWE questionnaire example

CVE-2021-45046  [log4j-core 2.14.1]  CWE-502 Deserialization of Untrusted Data
CVSS: 9.0 CRITICAL

  Q1: Does your package call the affected deserialization functions from this library?
  [y/n/s] > n

  => Status: not_affected
     Justification: vulnerable_code_not_in_execute_path

Output

{
  "@context": "https://openvex.dev/ns/v0.2.0",
  "@id": "urn:uuid:49fdfaa8-4c9c-433c-a627-aa88deb11b87",
  "author": "SecPod Technologies",
  "statements": [
    {
      "vulnerability": { "name": "CVE-2021-45046", "@id": "https://nvd.nist.gov/vuln/detail/CVE-2021-45046" },
      "products": [{ "@id": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1" }],
      "status": "not_affected",
      "justification": "vulnerable_code_not_in_execute_path",
      "impact_statement": "CVE-2021-45046 does not affect log4j-core@2.14.1 because the vulnerable code path is not reachable through this package's public API."
    }
  ]
}

CLI Reference

Command What it does
vex-studio assess [target] Primary workflow — SBOM + scan + triage + publish in one guided process
vex-studio generate-sbom [target] Generate a CycloneDX SBOM from a Python env, requirements file, or PURL list
vex-studio scan <sbom> Scan an SBOM for CVEs via OSV.dev and GHSA
vex-studio triage CWE-guided interactive triage for each CVE (uses latest scan)
vex-studio publish Generate VEX documents from a saved triage session
vex-studio status Show triage progress for the current session
vex-studio init Save author name and package PURL to .vex-studio.toml
vex-studio clean Remove scan results, sessions, VEX outputs, and/or logs

assess options

vex-studio assess [OPTIONS] [TARGET]

  TARGET            Project directory, requirements.txt, or '.' (default: .)
  -p, --purl        Build SBOM from one or more PURLs (repeatable)
  --sbom PATH       Skip SBOM generation and use an existing SBOM file
  --severity        Minimum CVE severity: critical | high | medium | low | all
  --author TEXT     Author name for the VEX document
  --product-purl    Override product PURL in the output
  --no-publish      Stop after triage; do not generate VEX output
  --vexhub          Write VEX in Aqua VEX Hub directory layout
  --save-sbom PATH  Save the generated SBOM to a specific path
  --no-ghsa         Skip GitHub Security Advisories enrichment

generate-sbom — supported inputs

Input Example
Python requirements file vex-studio generate-sbom requirements.txt
Python project directory vex-studio generate-sbom .
Current Python venv vex-studio generate-sbom
PURL — Python vex-studio generate-sbom -p pkg:pypi/django@3.2.0
PURL — Maven vex-studio generate-sbom -p pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1
PURL — npm vex-studio generate-sbom -p pkg:npm/express@4.18.2
Multiple PURLs vex-studio generate-sbom -p pkg:pypi/flask@2.0.0 -p pkg:npm/lodash@4.17.21
Any language (via syft) vex-studio generate-sbom . --method syft

For non-Python projects (npm, Maven, Go, etc.) via project directory, Syft must be installed.

Step-by-step workflow (alternative to assess)

# 1. Generate SBOM
vex-studio generate-sbom requirements.txt

# 2. Scan for CVEs
vex-studio scan sbom.cdx.json

# 3. Triage interactively
vex-studio triage

# 4. Publish VEX
vex-studio publish

# 5. Publish to Aqua VEX Hub layout
vex-studio publish --vexhub

Supported Formats

Input Output
CycloneDX JSON SBOM
SPDX JSON SBOM
OpenVEX 0.2.0 ✅ Phase 1
CSAF 2.0 Planned Phase 2
CycloneDX VEX Planned Phase 2

CVE data sources (all free, no API keys required):

Source Used for
OSV.dev CVEs for PyPI, npm, Maven, Go, crates.io, NuGet, and more
GitHub Security Advisories GHSA enrichment — additional CVEs and severity data
NVD CWE mappings (Phase 2)
CISA KEV Known exploited vulnerabilities (Phase 2)

VEX Status Values

Status Meaning
not_affected The CVE does not affect this package (with justification code)
affected The CVE is exploitable; remediation action recommended
fixed The fix has been applied in this version
under_investigation Still being assessed

Justification codes (for not_affected)

Code Meaning
component_not_present The vulnerable component is not in the build
vulnerable_code_not_present The vulnerable code does not exist in this version
vulnerable_code_not_in_execute_path The vulnerable code cannot be reached through the public API
inline_mitigations_already_exist A mitigation in the package prevents exploitation

Comparison with Existing Tools

Existing tools solve format generation — you tell them the status and they format a VEX document. VEX Studio solves exploitability determination — it helps you figure out what the status should be and then emits the same format.

PROBLEM 1: FORMAT GENERATION           <- vexctl, lib4vex, vexy solve this
PROBLEM 2: EXPLOITABILITY DETERMINATION  <- VEX Studio solves this
Capability vexctl lib4vex vexy VEX Studio
Discover CVEs automatically - - partial
Parse SBOM (CycloneDX + SPDX JSON) - - partial
Generate SBOM from env / PURL / requirements - - -
CWE-guided exploitability questionnaire - - -
Auto-suggest upgrade path (semver-aware) - - -
Audit trail of questions and answers - - -
Resume interrupted triage sessions - - -
Output: OpenVEX -
Output: CSAF / CycloneDX VEX - Phase 2
VEX Hub-compatible publish layout - - -
Cosign / sigstore signing - - Phase 2

Use them together

# VEX Studio: discover, decide, write VEX
vex-studio assess -p pkg:oci/myapp@sha256:abc123

# vexctl: sign and attach to a container image as an in-toto attestation
vexctl attest --attest --sign \
  --product="oci://ghcr.io/myorg/myapp:1.0" \
  .vex/myapp-1.0.openvex.json

Publishing to VEX Hub

Aqua VEX Hub is consumed automatically by Trivy. Once your VEX document is registered there, Trivy suppresses the corresponding false positives for all users of your package globally.

# Write VEX in VEX Hub directory layout
vex-studio assess -p pkg:pypi/mypackage@1.0.0 --vexhub

# This creates:
# .vex/pypi/mypackage/mypackage.openvex.json

# Then follow Aqua VEX Hub registration:
# https://github.com/aquasecurity/vexhub#submitting-vex-documents

Development

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
python -m pytest tests/

# Run tests with coverage
python -m pytest tests/ --cov=vex_studio --cov-report=term-missing

# Lint
ruff check src/

# Type check
mypy src/

Run without installing

python -m vex_studio.main --help
python -m vex_studio.main assess -p pkg:pypi/django@3.2.0

Project layout

src/vex_studio/
├── main.py               CLI entry point (Typer)
├── config.py             AppConfig (pydantic-settings)
├── models/               Pydantic data contracts (SBOM, vulnerability, triage, VEX)
├── parsers/              CycloneDX + SPDX SBOM parsers
├── clients/              OSV.dev + GHSA API clients
├── triage/               CWE questionnaire engine (the core IP)
│   ├── cwe_catalog.py    Question bank: CWE -> decision tree
│   ├── questionnaire.py  Question selector per CVE
│   ├── decision.py       Answer resolver -> VexStatus + justification
│   └── engine.py         Interactive triage orchestrator
├── vex/                  VEX document generation
│   ├── builder.py        OpenVEX direct writer + lib4vex adapter
│   └── hub.py            Aqua VEX Hub layout writer
└── cli/
    ├── commands/         One file per sub-command
    └── display.py        Rich tables and panels

See Architecture.md for full design documentation.


Roadmap

Phase Scope Status
1 Core CLI: assess, scan, triage, publish (OpenVEX), VEX Hub ✅ Complete
2 NVD CWE enrichment, CISA KEV, EPSS, CSAF/CycloneDX output, signing Planned
3 FastAPI backend + React web UI, AI-assisted triage Future

See PLAN.md for detailed task tracking.


Contributing

Contributions are welcome. Please open an issue before starting work on a significant change.

The most impactful contribution area is expanding the CWE questionnaire catalog in src/vex_studio/triage/cwe_catalog.py. Currently covers the OWASP/SANS Top 25 CWEs. Adding well-researched questions for additional CWEs directly improves the quality of VEX determinations for maintainers.

# Fork, clone, create a branch
git checkout -b feature/cwe-125-out-of-bounds-read

# Install dev dependencies
pip install -e ".[dev]"

# Make changes and run tests
python -m pytest tests/
ruff check src/

# Open a pull request

License

Apache 2.0 — see LICENSE.

Copyright 2026 SecPod Technologies — secpod.com

Note: secpod-vex-studio is not yet published to PyPI. Install from source as shown above.

About

Guided VEX authoring for OSS maintainers — from zero to a published VEX document in one command.

Topics

Resources

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages