Skip to main content

vex logo

vex

IOC enrichment hub for SOC triage and DFIR — VirusTotal + AbuseIPDB / Shodan / WHOIS / MISP / OpenCTI, straight from your terminal.

 ██╗   ██╗███████╗██╗  ██╗
 ██║   ██║██╔════╝╚██╗██╔╝
 ██║   ██║█████╗   ╚███╔╝
 ╚██╗ ██╔╝██╔══╝   ██╔██╗
  ╚████╔╝ ███████╗██╔╝ ██╗
   ╚═══╝  ╚══════╝╚═╝  ╚═╝

PyPI Python License


vex takes an indicator (a hash, IP, domain, or URL) and turns it into a verdict with context. It started as a VirusTotal CLI and grew into an enrichment hub: one primary source (VirusTotal) plus optional secondary sources that add reputation and your own threat-intel. It runs standalone, and it slots into a pipeline (barb → vex → sift) over stdin/stdout.

Install

pip install vex-ioc          # core
pip install vex-ioc[ai]      # + Anthropic / OpenAI explanations (Ollama needs no extra)

Quickstart

vex config --set-virustotal YOUR_VT_KEY  # or set VT_API_KEY
vex triage 8.8.8.8
vex triage evil.com --explain            # add an AI narrative
vex investigate <sha256> -o rich         # deep dive

Secondary enrichers (optional, saved to ~/.vex/config.yaml):

vex config --set-abuseipdb YOUR_KEY --set-shodan YOUR_KEY
vex config --set-misp-url URL --set-misp-key YOUR_KEY
vex config --set-opencti-url URL --set-opencti-token YOUR_TOKEN
IOC: 8.8.8.8 (ipv4)
Verdict: CLEAN
Detections: 0 malicious / 0 suspicious / 94 engines
Reputation: 0

What you get

  • Two modes — triage (fast verdict, minimal API calls) and investigate (deep DFIR: PE info, sandbox behavior, passive DNS, relationships, MITRE ATT&CK, timeline).
  • Multi-source enrichment — VirusTotal primary; AbuseIPDB, Shodan, WHOIS, MISP, and OpenCTI as secondary enrichers (key-gated, fail-open).
  • Batch correlation — --correlate clusters a batch of IOCs by shared infrastructure (ASN, malware family, contacted IPs/domains).
  • AI explanations — opt-in --explain narratives (Claude / OpenAI / local Ollama / deterministic template), with prompt-injection defense on the untrusted data fed to the model.
  • Pipeline-ready output — JSON, NDJSON (streaming), CSV, STIX 2.1, ATT&CK Navigator, self-contained HTML; verdict-mapped exit codes.
  • Quota-aware batches — IOC dedup, an up-front ETA, a --max-quota budget guard, and a persistent daily VT-quota counter with a stderr status line (on main, pending 1.7.0).
  • Local knowledge base — vex tag / note / watchlist annotate IOCs in ~/.vex/. Re-triage an entire watchlist in one shot with vex watchlist run <name> (on main, pending 1.7.0).
  • TI write-back (on main, pending 1.7.0) — vex investigate --sight writes MISP sightings and OpenCTI observables for IOCs above a configurable verdict floor; triple opt-in (config killswitch + flag + dry-run preview).

Verdicts

Verdict Meaning
🟢 CLEAN No engine flagged it.
🟡 UNKNOWN Not enough data, or the IOC was not found.
🟠 SUSPICIOUS Low-confidence detections.
🔴 MALICIOUS Meets the malicious-detection threshold.

Enrichment sources

VirusTotal is the primary source; it produces the verdict. The others are secondary enrichers that augment an investigate result.

Source IOC types Enable via
VirusTotal all VT_API_KEY / --api-key / vex config
AbuseIPDB IP VEX_ABUSEIPDB_API_KEY
Shodan IP VEX_SHODAN_API_KEY
WHOIS domain core (no key)
MISP all MISP_URL + MISP_API_KEY
OpenCTI all OPENCTI_URL + OPENCTI_TOKEN

Correlation

vex triage -f iocs.txt --correlate            # deterministic cluster table
vex triage -f iocs.txt --correlate --explain  # + per-cluster AI campaign narrative

--correlate groups a batch by shared ASN, malware family, contacted IPs, and contacted domains — surfacing likely campaigns. It is deterministic by default; the AI narrative is added only when --explain is also set.

AI explanations

--explain adds a narrative and next steps; --explain-model overrides the model. Providers: Anthropic, OpenAI, local Ollama, and a deterministic template fallback when none is configured.

export VEX_AI_PROVIDER=ollama        # local, no cloud key
vex investigate evil.com --explain

Output formats

-o rich (default TTY) · -o console · -o json · -o ndjson (one result per line, streamed) · --csv · --stix · --navigator (ATT&CK layer, investigate) · --html <path> (self-contained report). All formats show real IOCs by default; --defang defangs them (e.g. evil[.]com); HTML reports always defang.

sift triage alerts.json -o json | vex triage --from-sift -o ndjson

Pipeline

flowchart LR
    barb -->|URLs / IOCs| vex
    vex -->|enriched IOCs| sift
    sift -.->|extracted IOCs| vex

vex is the enrichment hub. --from-barb reads barb JSON; --from-sift reads a sift TriageReport, extracts its IOCs, and enriches them — closing the sift ↔ vex loop. NDJSON output and verdict exit codes make it scriptable downstream.

Scale

For large batches, such as IOCs extracted from a SIEM export:

  • Dedup — duplicate IOCs are collapsed before any query, which saves quota; --no-dedup disables it.
  • ETA + counters — an up-front estimate and a processed (N from API, M cached) summary on stderr.
  • --max-quota N — caps fresh API lookups; cached IOCs are still served, the rest are skipped with a notice. Re-run to continue — the SQLite cache resumes where you left off.

Configuration

Priority: --api-key flag → environment variable → ~/.vex/config.yaml → defaults.

vex config --show        # active config, masked secrets
vex doctor               # what's configured (no network)
vex doctor --probe       # + live connectivity, surfaces the actual error
Variable Purpose
VT_API_KEY VirusTotal
VEX_AI_API_KEY / VEX_AI_PROVIDER / VEX_AI_MODEL AI provider
VEX_ABUSEIPDB_API_KEY AbuseIPDB enricher
VEX_SHODAN_API_KEY Shodan enricher
MISP_URL / MISP_API_KEY MISP lookup
OPENCTI_URL / OPENCTI_TOKEN OpenCTI lookup

enrichment.stix_tlp_version (1.0 default, 2.0) selects which STIX TLP marking ids the export emits.

TI write-back (on main — pending 1.7.0)

vex investigate --sight writes MISP sightings and OpenCTI observables back for IOCs that meet a configurable verdict floor. Three gates must all be open before any write occurs:

  1. enrichment.writeback_enabled: true in ~/.vex/config.yaml (default false).
  2. --sight flag on vex investigate.
  3. Use --dry-run-sight first to preview the payloads without sending.
vex investigate 1.2.3.4 --dry-run-sight     # preview payloads, no network
vex investigate 1.2.3.4 --sight             # write if enabled and above floor
vex investigate -f iocs.txt --sight         # batch write-back

Key config keys (in enrichment: section):

Key Default Meaning
writeback_enabled false Master switch — must be true or --sight is a no-op.
writeback_tlp "green" TLP ceiling. Writes are blocked when the IOC's source TLP is more restrictive.
writeback_min_verdict "SUSPICIOUS" Verdict floor — IOCs below this are silently skipped.

Security

Exit codes

Computed from the highest-severity verdict in the run:

Code Meaning
0 CLEAN / UNKNOWN
1 SUSPICIOUS — or a runtime error / bad input
2 MALICIOUS

Known limitations

  • MISP (v2.5.38) and OpenCTI (demo v7.26) lookups are live-verified end-to-end, and both have mock tests. They query real instances and stay version-sensitive: if a server's schema differs, the enricher fails open (no enrichment, no crash). Use vex doctor --probe to confirm connectivity. pycti is a possible future fallback if OpenCTI's GraphQL schema drifts.
  • AI: Anthropic and Ollama are live-verified end-to-end; OpenAI shares the same code path (mock-tested). Without a provider, --explain falls back to a deterministic template.
  • Secondary enrichers run on investigate, not triage. A triage --explain gets no AbuseIPDB / Shodan / MISP / OpenCTI context by design.
  • STIX TLP:CLEAR maps to the TLP 1.0 WHITE marking id by default — set enrichment.stix_tlp_version: "2.0" to switch to TLP 2.0 ids.
  • The VirusTotal free tier allows roughly 4 requests/min, so large batches are quota-bound — see Scale.

Docs

Full manual: docs/ — getting started, every command/flag, the enrichment model, output formats, the barb/sift pipeline contracts, and configuration. Built-in guide: vex manual (and vex manual ai / pipeline / config). Changelog: CHANGELOG.md.

Author

Christian Huhn — building security tooling for SOC/DFIR workflows.

License

MIT

Metadata

Release files for vex-ioc 1.8.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vex-ioc 1.8.1
File Size Uploaded Provenance Actions
vex_ioc-1.8.1.tar.gz 193.9 kB With provenance Details for vex_ioc-1.8.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for vex-ioc 1.8.1
File Interpreter ABI Platform Actions
vex_ioc-1.8.1-py3-none-any.whl Python 3 none any Details for vex_ioc-1.8.1-py3-none-any.whl

Total release size: 319.1 kB

Release files / vex_ioc-1.8.1.tar.gz

Download URL vex_ioc-1.8.1.tar.gz
Size 193.9 kB
Tags Source
SHA-256 checksum
How to use checksums
6abfb673ea3d022b3775d3951c67e8f9e56fa3fe5f7a312c3a615cb30853fb1e
BLAKE2b-256 checksum
How to use checksums
622887139a2c6b3194f8693496dd9881094943ec7a9077403212abb5da461fb4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.

Transparency log

Release files / vex_ioc-1.8.1-py3-none-any.whl

Download URL vex_ioc-1.8.1-py3-none-any.whl
Size 125.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1f7abe0d3d2d8b89dd3768056f3ebc061ba2040a2ec319dcae1292d0d118743a
BLAKE2b-256 checksum
How to use checksums
647630dec5ba965305c96f565c2ad663b3e9caf95ff598259530171abc058b65
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.

Transparency log

Security for vex-ioc 1.8.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for vex_ioc-1.8.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page