Skip to main content

VirusTotal IOC Enrichment Tool for SOC/DFIR workflows

Project description

vex logo

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) and investigate (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
  • IOC defanging/refanging for safe sharing (hxxps[://]evil[.]com)
  • Automation-ready: exit codes, --alert filtering, --summary on 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
  • SQLite cache with configurable TTL (default 24h)
  • Rate limiting: token-bucket, free tier (4 req/min) and premium configurable

Setup

Prerequisites

Installation

From PyPI (recommended):

pip install vex-ioc

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

# Automation: exit code + alert filter + summary
vex triage -f iocs.txt --alert SUSPICIOUS --summary
echo $?  # 0=clean, 1=suspicious, 2=malicious

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 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

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)

Configuration Command

Manage vex configuration:

# Save API key permanently
vex config --set-api-key YOUR_KEY

# Show usage
vex config

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.

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.1.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
├── batch.py             # Parallel batch processing
├── timeline.py          # Timeline event reconstruction
├── vex.png              # Logo
├── 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
└── output/
    ├── formatter.py     # Rich + console + timeline formatters
    ├── export.py        # JSON + CSV export
    └── stix.py          # STIX 2.1 bundle generation

Changelog

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 remains vex
  • 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 Huhngithub.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

vex_ioc-1.1.1.tar.gz (43.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vex_ioc-1.1.1-py3-none-any.whl (50.7 kB view details)

Uploaded Python 3

File details

Details for the file vex_ioc-1.1.1.tar.gz.

File metadata

  • Download URL: vex_ioc-1.1.1.tar.gz
  • Upload date:
  • Size: 43.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for vex_ioc-1.1.1.tar.gz
Algorithm Hash digest
SHA256 4b5874e54483159e005c8753281b16a85b23a34230db1b4b310b623d7b62445e
MD5 c3339d5044e17efc34ca74e12e8e9f64
BLAKE2b-256 321d2780d765f78af776a08aff36a279fb2064235198380a9e1bf9babf6d8c76

See more details on using hashes here.

Provenance

The following attestation bundles were made for vex_ioc-1.1.1.tar.gz:

Publisher: publish.yml on duathron/vex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vex_ioc-1.1.1-py3-none-any.whl.

File metadata

  • Download URL: vex_ioc-1.1.1-py3-none-any.whl
  • Upload date:
  • Size: 50.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for vex_ioc-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 17b3c7b961288adb92d7111b9554717ffa0102ffcb55370a579bea1d3944305d
MD5 c39185adf128b18bee709d1ed602f3f2
BLAKE2b-256 957e0c543ed5579652beecd507625bf23ec9389510fc9cbfd266effc61a9a596

See more details on using hashes here.

Provenance

The following attestation bundles were made for vex_ioc-1.1.1-py3-none-any.whl:

Publisher: publish.yml on duathron/vex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page