VirusTotal IOC Enrichment Tool for SOC/DFIR workflows
Project description
vex
VirusTotal IOC enrichment for SOC triage and DFIR investigations, straight from your terminal.
██╗ ██╗███████╗██╗ ██╗
██║ ██║██╔════╝╚██╗██╔╝
██║ ██║█████╗ ╚███╔╝
╚██╗ ██╔╝██╔══╝ ██╔██╗
╚████╔╝ ███████╗██╔╝ ██╗
╚═══╝ ╚══════╝╚═╝ ╚═╝
Features
- Auto-detection of IOC types: MD5, SHA1, SHA256, IPv4, IPv6, Domain, URL
- Two modes:
triage(fast, 1 API call) andinvestigate(deep, multiple calls) - Output formats: JSON (default), Rich tables, plain console, CSV, STIX 2.1
- MITRE ATT&CK mapping from sandbox behaviors and VT tags
- ATT&CK Navigator export:
--navigatorto export ATT&CK layer JSON for Navigator - IOC defanging/refanging for safe sharing (
hxxps[://]evil[.]com) - Automation-ready: exit codes,
--alertfiltering,--summaryon stderr - Timeline enrichment: chronological event reconstruction for DFIR
- Local knowledge base: tag, annotate, and watchlist IOCs in SQLite
- Plugin architecture: extensible enrichment sources via Protocol interface
- Parallel batch processing with progress bar for large IOC lists
- STIX 2.1 export for threat intelligence sharing
- WHOIS enrichment: direct WHOIS lookups for domain IOCs (included in base install)
- SQLite cache with configurable TTL (default 24h)
- AI-powered explanations:
--explainfor threat narratives via Claude, OpenAI, or Ollama (opt-in) - barb pipeline:
--from-barbto combine barb heuristic pre-scan with VT enrichment - Addon discoverability:
vex addonsshows available extras and install status - Rate limiting: token-bucket, free tier (4 req/min) and premium configurable
Part of the security portfolio: Use barb for offline heuristic phishing URL triage. Use vex for VirusTotal IOC enrichment. Pipe barb JSON output into vex for full enrichment (v1.2).
Setup
Prerequisites
- Python 3.11+
- A VirusTotal API key (free tier works)
Installation
From PyPI (recommended):
pip install vex-ioc
# With AI support (Claude + OpenAI)
pip install vex-ioc[ai]
# Ollama (local models) works out of the box — no extras needed
# WHOIS enrichment is included in the base install (core dep since v1.2.0)
Kali Linux / Debian / system Python? Use
pipxto avoid system package conflicts:sudo apt install pipx && pipx ensurepath pipx install vex-ioc pipx install "vex-ioc[ai]" # with AI support
After installation, run vex addons to see all available extras and their status.
From source:
git clone https://github.com/duathron/vex.git
cd vex
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
pip install -e .
Upgrade
# If installed from PyPI
pip install --upgrade vex-ioc
# If installed from git clone (editable)
cd vex
git pull
pip install -r requirements.txt
pip install -e .
API Key
Set your API key using one of these methods (priority order):
# Option 1: Per-command flag (highest priority)
vex triage 8.8.8.8 --api-key YOUR_KEY
vex investigate evil.com -k YOUR_KEY
# Option 2: Environment variable
export VT_API_KEY="your-virustotal-api-key"
# Option 3: Save permanently to ~/.vex/config.yaml
vex config --set-api-key YOUR_KEY
# Option 4: Manual config.yaml or .env
# api:
# key: "your-key"
Quickstart
# Fast triage
vex triage 44d88612fea8a8f36de82e1278abb02f
# Rich terminal output
vex investigate evil-domain.com -o rich
# Batch from file, CSV export
vex triage -f iocs.txt --csv
# Pipe from another tool
echo "8.8.8.8" | vex triage -o rich
# Defanged IOC support
vex triage "hxxps[://]evil[.]com"
# STIX 2.1 export
vex investigate evil.com --stix > bundle.json
# Timeline reconstruction
vex investigate evil.com -o rich --timeline
# AI-powered explanation (template fallback if no LLM configured)
vex triage 44d88612fea8a8f36de82e1278abb02f --explain
# With Claude as AI provider
vex investigate evil.com -o rich --explain --explain-model claude-sonnet-4-20250514
# Show active configuration
vex config --show
# Automation: exit code + alert filter + summary
vex triage -f iocs.txt --alert SUSPICIOUS --summary
echo $? # 0=clean, 1=suspicious, 2=malicious
# barb → vex pipeline (combine heuristic pre-scan with VT enrichment)
barb analyze https://evil.com -o json | vex triage --from-barb -o rich
barb analyze https://evil.com -o json | vex investigate --from-barb -o rich
# ATT&CK Navigator layer export
vex investigate evil.com --navigator > layer.json
# Open layer.json at https://mitre-attack.github.io/attack-navigator/
# Domain WHOIS enrichment (included in base install since v1.2.0)
vex investigate evil.com -o rich # WHOIS panel shown automatically
Documentation
Subcommands
| Command | Description |
|---|---|
vex triage <ioc> |
Fast SOC triage (1 API call) |
vex investigate <ioc> |
Deep DFIR investigation (multiple calls) |
vex config |
Manage configuration (save API key, etc.) |
vex cache-clear |
Clear the SQLite result cache |
vex version |
Show version |
vex addons |
Show available extras and installation status |
vex tag <ioc> |
Manage IOC tags in local knowledge base |
vex note <ioc> |
Manage IOC notes in local knowledge base |
vex watchlist <name> |
Manage IOC watchlists |
vex manual [topic] |
Show usage guide (topics: ai, config, examples, pipeline, addons) |
Triage / Investigate Options
| Flag | Description |
|---|---|
-k / --api-key |
VirusTotal API key (overrides env var & config) |
-q / --quiet |
Suppress the ASCII banner |
-o / --output |
Output format: json | rich | console (default: console) |
-f / --file |
File with one IOC per line |
-c / --config |
Custom config.yaml path |
--no-cache |
Bypass cache, force fresh lookup |
--csv |
CSV output (triage only) |
--defang |
Defang IOCs in output |
--stix |
Export as STIX 2.1 JSON bundle |
--alert <LEVEL> |
Only show results >= verdict level |
--summary |
Print verdict summary to stderr |
--timeline |
Show chronological timeline (investigate only) |
-e / --explain |
Add AI-powered threat explanation to output |
--explain-model |
Override AI model (e.g. claude-sonnet-4-20250514, gpt-4o, llama3) |
--from-barb |
Read barb JSON from stdin, use URLs as IOCs (triage & investigate) |
--navigator |
Export ATT&CK Navigator layer JSON to stdout (investigate only) |
Configuration Command
Manage vex configuration:
# Save API key permanently
vex config --set-api-key YOUR_KEY
# Show active configuration (API keys masked)
vex config --show
Saved config is stored at ~/.vex/config.yaml with restricted permissions (0o600).
IOC Types
| Type | Example |
|---|---|
| MD5 | 44d88612fea8a8f36de82e1278abb02f |
| SHA1 | 3395856ce81f2b7382dee72602f798b642f14140 |
| SHA256 | 275a021bbfb6489e54d471899f7db9d1663fc695... |
| IPv4 | 8.8.8.8 |
| IPv6 | 2001:4860:4860::8888 |
| Domain | example.com |
| URL | https://example.com/malware.exe |
Defanged IOCs are automatically refanged before lookup:
hxxps[://]evil[.]com becomes https://evil.com.
Verdict System
| Verdict | Condition | Exit Code |
|---|---|---|
| MALICIOUS | >= 3 malicious detections | 2 |
| SUSPICIOUS | >= 1 malicious detection | 1 |
| UNKNOWN | Zero detections OR too few engines | 0 |
| CLEAN | Zero detections AND enough engines | 0 |
Zero detections does not mean CLEAN. If too few engines reported, the verdict is UNKNOWN.
MITRE ATT&CK Mapping
In investigate mode, vex maps sandbox behaviors and VT tags to MITRE ATT&CK techniques. Mappings cover 80+ keywords across all major tactics (Execution, Persistence, Defense Evasion, etc.) and appear in Rich output and STIX exports.
ATT&CK Navigator Export
Export investigation results as an ATT&CK Navigator v4.5 layer JSON:
# Export a Navigator layer
vex investigate evil.com --navigator > layer.json
# Open layer.json at https://mitre-attack.github.io/attack-navigator/
# Click "Open Existing Layer" → upload layer.json
The layer visualizes all mapped techniques with a red heat gradient, tactic labels, and evidence comments. Requires at least one investigate result with ATT&CK mappings.
WHOIS Enrichment
In investigate mode, vex automatically performs a direct WHOIS lookup for domain IOCs. This is especially useful for free-tier VT users (VT WHOIS is a premium feature). python-whois is included in the base install since v1.2.0 — no extra needed.
# WHOIS data appears automatically in rich/console output
vex investigate evil.com -o rich
To disable: set enrichment.whois_enabled: false in ~/.vex/config.yaml.
barb → vex Pipeline
Combine barb offline heuristic analysis with VirusTotal live enrichment:
# Install barb
pip install barb-phish
# Pipe barb JSON into vex triage
barb analyze https://evil.com -o json | vex triage --from-barb -o rich
# Deep investigation with barb context
barb analyze https://evil.com -o json | vex investigate --from-barb -o rich
# Batch: screen multiple URLs, enrich high-risk ones
barb analyze -f urls.txt -o json | vex triage --from-barb --alert SUSPICIOUS -o rich
# JSON output includes barb_context field
barb analyze https://evil.com -o json | vex triage --from-barb -o json
Workflow: barb runs offline (no HTTP requests to target), providing instant verdict + signal breakdown. vex then enriches with live VT detection data. The --from-barb flag reads barb's JSON from stdin, extracts URLs as IOCs, and displays a "barb pre-scan" panel alongside VT results.
See vex manual pipeline for full documentation.
Knowledge Base
Manage local IOC metadata that persists across sessions:
# Tag IOCs
vex tag 8.8.8.8 --add dns --add google
vex tag 8.8.8.8 # list tags
# Add notes
vex note evil.com --add "Seen in phishing campaign Q4"
vex note evil.com # list notes
# Watchlists
vex watchlist priority --add 8.8.8.8 --add evil.com
vex watchlist priority --list
Plugin Architecture
vex uses a Protocol-based plugin system. The built-in VirusTotal plugin implements EnricherProtocol. Third-party sources (OTX, AbuseIPDB, etc.) can be added by implementing the same protocol.
Config Reference
api:
# key: "your-key" # or set VT_API_KEY env var
tier: free # free | premium
rate_limit:
free:
requests_per_minute: 4
requests_per_day: 500
premium:
requests_per_minute: 1000
requests_per_day: 50000
thresholds:
malicious_min_detections: 3
suspicious_min_detections: 1
min_engines_for_clean: 10
cache:
enabled: true
ttl_hours: 24
# db_path: "/custom/path/cache.db" # default: ~/.vex/cache.db
output:
default_format: json
quiet: false # suppress banner (-q)
Project Structure
vex/
├── __init__.py # Package version (1.2.0)
├── main.py # Typer CLI app with all subcommands
├── banner.py # ASCII art banner (ffuf-style)
├── client.py # Sync VT API v3 client + rate limiter
├── async_client.py # Async VT API client for parallel ops
├── config.py # Pydantic config from config.yaml
├── cache.py # SQLite result cache with TTL
├── ioc_detector.py # Regex auto-detection of IOC types
├── defang.py # IOC defanging/refanging
├── models.py # Pydantic v2 models + Verdict enum
├── addons.py # Addon registry + get_addon_status()
├── batch.py # Parallel batch processing
├── timeline.py # Timeline event reconstruction
├── version_check.py # PyPI update check
├── vex.png # Logo
├── ai/
│ ├── __init__.py # Provider factory + availability
│ ├── protocol.py # LLMProviderProtocol interface
│ ├── prompt.py # Prompt builder (input sanitization)
│ ├── template.py # Template-based fallback (no LLM)
│ ├── cache.py # AI response cache (SQLite, 72h TTL)
│ ├── anthropic.py # Claude provider
│ ├── openai.py # OpenAI provider
│ └── ollama.py # Ollama local provider
├── enrichers/
│ ├── base.py # Shared enricher utilities
│ ├── protocol.py # EnricherProtocol interface
│ ├── hash.py # MD5/SHA1/SHA256 enrichment
│ ├── ip.py # IPv4/IPv6 enrichment
│ ├── domain.py # Domain enrichment
│ └── url.py # URL enrichment
├── plugins/
│ ├── registry.py # Plugin discovery & registration
│ ├── loader.py # Plugin loading
│ └── virustotal.py # Built-in VT plugin
├── mitre/
│ ├── mapping.py # VT behavior → ATT&CK technique dict
│ └── mapper.py # Result → ATT&CK mapping engine
├── knowledge/
│ ├── db.py # SQLite knowledge base (tags/notes/watchlists)
│ └── api.py # High-level knowledge base API
├── pipeline/
│ ├── __init__.py # Package marker
│ └── barb_bridge.py # barb JSON parser, BarbContext model
└── output/
├── formatter.py # Rich + console + timeline + barb formatters
├── export.py # JSON + CSV export
├── stix.py # STIX 2.1 bundle generation
└── navigator.py # ATT&CK Navigator layer export
Changelog
2026-03-18
- v1.2.0 — AI integration:
--explainflag for AI-powered threat narratives (Claude, OpenAI, Ollama), template-based fallback, AI response caching (72h),vex config --show, optional deps (pip install vex-ioc[ai]) - v1.2.0 — barb pipeline:
--from-barbto pipe barb heuristic JSON into vex triage/investigate, barb pre-scan panel in Rich/console output,barb_contextfield in JSON output - v1.2.0 — WHOIS enrichment: direct WHOIS lookups for domains via python-whois (now a core dependency), free-tier supplement for VT premium WHOIS
- v1.2.0 — ATT&CK Navigator export:
--navigatorto generate Navigator v4.5 layer JSON from investigation results - v1.2.0 —
vex manual pipelinetopic, updatedvex manual exampleswith new flags - v1.2.0 — Addon discoverability (MeetUp VEX-2026-007):
vex addonscommand, addon status invex config --show, one-time first-run hint,vex manual addonstopic, AI/Template explanation labels - v1.2.0 —
pipxinstall documented for Kali/Debian/system-Python environments
2026-03-16
- v1.1.0 — Resolved all known limitations: batch processing activated, premium endpoint graceful degradation, entry-point plugin discovery, IPv6 detection upgraded to RFC 4291, passive version update check
- PyPI — Package published as
vex-ioc(pip install vex-ioc); CLI command remainsvex - CI/CD — GitHub Actions workflow added: automatic PyPI publish on
v*.*.*tag push - License — LICENSE.md added (MIT)
- v1.0.1 — UX improvements: color-coded console verdicts, batch failure count, alert filter feedback, config.yaml.example schema fix, consistent list truncation
2026-03-13
- v1.0.0 — Initial release: triage & investigate, MITRE ATT&CK mapping, STIX 2.1, knowledge base, timeline, plugin architecture, rate limiting, SQLite cache
Built by Christian Huhn — github.com/duathron/vex
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vex_ioc-1.2.0.tar.gz.
File metadata
- Download URL: vex_ioc-1.2.0.tar.gz
- Upload date:
- Size: 64.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b5ce847f4c0d544d8a23a76681bf0e24ad5cad8883dadd3bf12b3db222270c77
|
|
| MD5 |
fac3661fa6753047accb85cd268698fe
|
|
| BLAKE2b-256 |
ee37ba155d3b008d1833352a0d2caa1a5b3a7489aa0fd60936e4df16f3b243a5
|
Provenance
The following attestation bundles were made for vex_ioc-1.2.0.tar.gz:
Publisher:
publish.yml on duathron/vex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vex_ioc-1.2.0.tar.gz -
Subject digest:
b5ce847f4c0d544d8a23a76681bf0e24ad5cad8883dadd3bf12b3db222270c77 - Sigstore transparency entry: 1154564772
- Sigstore integration time:
-
Permalink:
duathron/vex@ff805342b1a40486f50bad65919d356221cf1673 -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/duathron
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff805342b1a40486f50bad65919d356221cf1673 -
Trigger Event:
push
-
Statement type:
File details
Details for the file vex_ioc-1.2.0-py3-none-any.whl.
File metadata
- Download URL: vex_ioc-1.2.0-py3-none-any.whl
- Upload date:
- Size: 74.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e11ada7f9ac30ea311ec23dcdb599cc70931a483d43aacc810d5f7e5549f49d5
|
|
| MD5 |
b720db5ddf756bd3ef95b107018b5e6a
|
|
| BLAKE2b-256 |
e68f18491a1bf103e1e4310b61397c1bae4f14d6e0739c08a377ffc12cd5c7f2
|
Provenance
The following attestation bundles were made for vex_ioc-1.2.0-py3-none-any.whl:
Publisher:
publish.yml on duathron/vex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vex_ioc-1.2.0-py3-none-any.whl -
Subject digest:
e11ada7f9ac30ea311ec23dcdb599cc70931a483d43aacc810d5f7e5549f49d5 - Sigstore transparency entry: 1154564778
- Sigstore integration time:
-
Permalink:
duathron/vex@ff805342b1a40486f50bad65919d356221cf1673 -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/duathron
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff805342b1a40486f50bad65919d356221cf1673 -
Trigger Event:
push
-
Statement type: