Investigate IPs, domains, hashes, and CVEs across 6 free threat intel APIs โ without switching between browser tabs.
Quick Start ยท Usage ยท Architecture ยท API Keys ยท Screenshots ยท Contributing
๐ Proudly featured in the official Awesome OSINT repository.
ThreatLens is a single command-line tool that unifies threat intelligence lookups across the most trusted free OSINT sources. Instead of pasting an IP into five different websites, ThreatLens queries them all in parallel, normalizes the results, and gives you a clear verdict โ in the terminal, or in a polished, color-coded Excel/JSON/CSV report.
Built for SOC analysts, incident responders, threat hunters, and anyone who wants fast, reliable IOC enrichment without leaving the shell.
|
Why ThreatLens
|
Not for
|
| Feature | Details |
|---|---|
| ๐ฏ IOC Types | IP, Domain, URL, File Hash (MD5 / SHA1 / SHA256), CVE |
| ๐ Integrated APIs | AbuseIPDB, VirusTotal, AlienVault OTX, Shodan, URLScan.io, NVD, CISA KEV, EPSS |
| ๐ Log Parsing | Auto-extract IOCs from plain text/log files, plus native support for Zeek, Suricata eve.json, Sysmon (JSON), and generic JSONL |
| ๐งญ CVE Decision Cards | Deterministic, explainable Patch / Isolate / Monitor / Not affected recommendation per CVE, driven by CISA KEV, EPSS, CVSS, and correlated asset exposure |
| ๐๏ธ Asset Inventory | Import a CSV of hosts/IPs with criticality and internet-facing status; correlated against CVE results |
| ๐ค SIEM Export | Opt-in export to Splunk HEC, Elastic _bulk, and Microsoft Sentinel (modern Logs Ingestion API) |
| ๐งพ Evidence Packs | ZIP export of an investigation with a SHA-256 manifest for basic chain-of-custody |
| ๐ Reports | Excel (color-coded), JSON, CSV |
| ๐พ Local Cache | SQLite cache with configurable TTL โ skip re-querying known IOCs, plus a cached CISA KEV feed (24h TTL) |
| ๐ก๏ธ Security | Redirect blocking, host allow-listing, API-key redaction in logs, spreadsheet-formula neutralisation, CSV/log DoS limits |
| ๐ Lockfile | requirements.lock with SHA-256 hashes for reproducible installs |
| ๐ป CLI Experience | Rich progress bars, colored tables, and a clean verdict summary |
| ๐งฉ Architecture | Modular enrichers/parsers/exporters, typed models, strict separation of concerns |
| โ Tested | 155 unit & integration tests with pytest; CI via GitHub Actions |
| โก Resilient | One failing API or SIEM destination never blocks the others โ errors are isolated and logged |
# 1. Clone & install
git clone https://github.com/AbdaullahAG/threatlens.git
cd threatlens
pip install -r requirements.txt
# 2. Configure your API keys
cp config/keys.env.example config/keys.env
# โ edit config/keys.env and fill in your keys
# 3. Run your first scan
python main.py -i 45.33.32.156๐ก NVD (CVE lookups) works out of the box with no API key. Every other API offers a free tier that takes under 2 minutes to sign up for โ see API Keys below.
pip install --require-hashes -r requirements.lock
# Investigate a single IP
python main.py -i 45.33.32.156 | Basic single-IOC lookup |
# Investigate multiple IOC types at once
python main.py -i 45.33.32.156 -d malware.example.com \
-s d41d8cd98f00b204e9800998ecf8427e -c CVE-2021-44228 | Mix and match IOC types in one run |
# Parse a log file โ all IOCs auto-extracted
python main.py --file /var/log/apache2/access.log | Bulk investigate straight from raw logs |
# Output JSON instead of Excel
python main.py -i 8.8.8.8 --format json | Machine-readable output for pipelines |
# Use only specific APIs
python main.py -i 8.8.8.8 --apis abuseipdb virustotal | Restrict enrichment to selected sources |
# Generate every report format at once
python main.py --file access.log --format all | Excel + JSON + CSV in a single run |
# Lookup a CVE โ no API key needed
python main.py -c CVE-2021-44228 --apis nvd --format json | CVE enrichment via NIST NVD (free, no key) |
# Verbose / debug mode
python main.py -i 8.8.8.8 -v | Full request/response logging for troubleshooting |
# Check a CVE against CISA KEV + EPSS, with an asset-aware decision
python main.py -c CVE-2021-44228 --apis nvd cisa_kev epss \
--import-assets assets.csv --decision-cards | Patch / Isolate / Monitor / Not-affected recommendation |
# Parse a Suricata eve.json and export to Splunk
python main.py --file eve.json --log-format suricata \
--export splunk | SOC log ingestion โ SIEM export |
# Build a hash-manifested evidence pack for the investigation
python main.py -i 45.33.32.156 --evidence-pack | ZIP with a SHA-256 manifest for chain-of-custody |
See all CLI flags
| Flag | Description |
|---|---|
-i, --ip |
IP address(es) to investigate |
-d, --domain |
Domain(s) to investigate |
-s, --hash |
File hash(es) โ MD5 / SHA1 / SHA256 |
-c, --cve |
CVE ID(s), e.g. CVE-2021-44228 |
--file |
Path to a log/text file to auto-extract IOCs from |
--log-format |
Format of --file: auto (default) | text | zeek | suricata | sysmon | jsonl |
--apis |
Restrict enrichment to a specific set of APIs (now includes cisa_kev, epss) |
--format |
Output format: excel (default) | json | csv | all |
--output |
Directory to save reports (default: ./output) |
--no-report |
Print results to terminal only, skip saving a file |
--import-assets |
Import an asset inventory CSV (hostname/ip, criticality, internet_facing, owner, product) |
--decision-cards |
Produce a Patch/Isolate/Monitor/Not-affected card for every CVE result |
--export |
Send results to one or more SIEM destinations: splunk | elastic | sentinel (opt-in, must be configured in config/keys.env) |
--export-insecure-tls |
Disable TLS verification for SIEM export (testing only; logs a loud warning) |
--evidence-pack |
Package the investigation into a SHA-256-manifested ZIP |
--cache-path |
SQLite path for local cache (default: .threatlens/investigations.db) |
--cache-ttl |
Cache lifetime in seconds (default: 3600) |
--no-cache |
Bypass the local cache entirely |
--max-requests |
Cap on external API calls per run (default: 250) |
--max-iocs |
Maximum unique IOCs per run (default: 1000) |
--allow-private-iocs |
Allow private/loopback IPs (disabled by default) |
--delay |
Delay between API calls, for rate-limit tuning |
-v, --verbose |
Enable debug logging |
ThreatLens can go beyond IOC lookups into lightweight CVE triage and log ingestion:
- CISA KEV + EPSS enrich every CVE result alongside NVD's CVSS score. The KEV catalog (~1,600+ entries) is downloaded once and cached locally for 24h instead of being re-fetched per CVE; EPSS scores are batch-fetched for all CVEs in a run.
- CVE Decision Cards (
--decision-cards) turn that data into one of Patch / Isolate / Monitor / Not affected, using an explicit, auditable rule table (not a black-box score) โ every card includes the reasons behind it. A CISA KEV listing is a hard floor: it is never downgraded to "Monitor". - Asset Inventory (
--import-assets assets.csv) lets the decision logic factor in whether an affected product is actually running anywhere, and whether that asset is internet-facing and business-critical. Required CSV columns: a hostname/ip column pluscriticality(critical/high/medium/low); optional:internet_facing,owner,product. Matching is a best-effort heuristic (see the code docstrings for its documented limits) โ treat "Not affected" as "no match found," not an absolute guarantee. - Log parsers:
--filenow accepts--log-format zeek|suricata|sysmon|jsonl(orauto-detects) for Zeek TSV logs, Suricataeve.json, JSON-exported Sysmon events, and generic JSON-Lines logs โ all streamed line-by-line with size/row limits, so a single malformed line never aborts the scan. - SIEM export (
--export splunk elastic sentinel) is fully opt-in and only activates for destinations with complete credentials inconfig/keys.env. Sentinel uses the modern Logs Ingestion API (Entra ID app registration โ Data Collection Endpoint/Rule), not the deprecated HTTP Data Collector API. - Evidence packs (
--evidence-pack) bundle the investigation's results (and decision cards/matched assets, if produced) into a ZIP with amanifest.jsonrecording a SHA-256 hash of every file inside.
threat_intel_tool/
โโโ main.py # CLI entry point & argument parser
โโโ requirements.txt # Runtime dependencies
โโโ requirements-dev.txt # Dev/CI tooling (ruff, bandit, pip-audit, pip-tools)
โโโ requirements.lock # Pinned lockfile with SHA-256 hashes
โโโ pytest.ini # pytest configuration (marks, etc.)
โโโ config/
โ โโโ keys.env # API keys (copy from keys.env.example)
โโโ output/ # Generated reports land here
โโโ src/
โ โโโ engine.py # Main orchestrator (collect โ enrich โ decide โ report โ export)
โ โโโ models.py # IOC, EnrichmentResult & AssetRecord dataclasses
โ โโโ storage.py # SQLite cache, feed cache, investigation & asset history
โ โโโ parsers/
โ โ โโโ ioc_parser.py # Regex-based IOC extractor with validation (plain text/logs)
โ โ โโโ common.py # Shared streaming/validation helpers for log parsers
โ โ โโโ zeek.py # Zeek TSV logs (conn/dns/http/ssl/files.log)
โ โ โโโ suricata.py # Suricata eve.json (alert/dns/http/tls/fileinfo)
โ โ โโโ sysmon.py # Sysmon JSON-exported Windows Event Log (EIDs 1, 3)
โ โ โโโ jsonl.py # Generic, schema-agnostic JSON-Lines extractor
โ โโโ enrichers/
โ โ โโโ base.py # Abstract base โ safe HTTP client (redirect-block, budget, retry)
โ โ โโโ registry.py # Enricher dispatcher
โ โ โโโ abuseipdb.py # AbuseIPDB (IP)
โ โ โโโ virustotal.py # VirusTotal (IP / Domain / URL / Hash)
โ โ โโโ otx.py # AlienVault OTX (IP / Domain / URL / Hash)
โ โ โโโ shodan.py # Shodan (IP)
โ โ โโโ urlscan.py # URLScan.io (URL / Domain)
โ โ โโโ nvd.py # NVD / NIST (CVE โ no key required)
โ โ โโโ cisa_kev.py # CISA KEV (CVE โ cached bulk feed, no key required)
โ โ โโโ epss.py # FIRST.org EPSS (CVE โ batch-fetched, no key required)
โ โโโ decision/
โ โ โโโ cve_decision.py # Deterministic Patch/Isolate/Monitor/Not-affected logic
โ โ โโโ asset_correlation.py # CVE โ asset-inventory matching heuristic
โ โโโ assets/
โ โ โโโ importer.py # Safe CSV asset-inventory importer
โ โโโ exporters/
โ โ โโโ base.py # Allow-listed, retrying, TLS-verified HTTP POST client
โ โ โโโ splunk.py # Splunk HTTP Event Collector
โ โ โโโ elastic.py # Elasticsearch _bulk API
โ โ โโโ sentinel.py # Microsoft Sentinel โ modern Logs Ingestion API
โ โ โโโ dispatcher.py # Builds configured exporters, isolates per-destination failures
โ โโโ evidence/
โ โ โโโ pack.py # ZIP evidence pack with a SHA-256 manifest
โ โโโ reporters/
โ โ โโโ excel_reporter.py # Color-coded Excel reports
โ โ โโโ other_reporters.py # JSON & CSV output
โ โ โโโ terminal_display.py # Rich terminal tables
โ โโโ utils/
โ โโโ config.py # API key loader & runtime config
โ โโโ logger.py # Rich logging setup
โ โโโ banner.py # ASCII banner
โ โโโ quota.py # Per-run request budget (thread-safe)
โ โโโ security.py # IOC validation, formula neutralisation, secret redaction
โโโ tests/
โโโ conftest.py # pytest fixtures & --run-e2e flag
โโโ test_core.py # IOC parser, verdict logic, cache round-trip
โโโ test_enrichers.py # BaseEnricher HTTP edge-cases โ mock only
โโโ test_reporters.py # Excel/CSV formula protection + SQLite integration
โโโ test_vuln_intel_enrichers.py # CISA KEV + EPSS enrichers, feed cache
โโโ test_cve_decision.py # Deterministic CVE Decision Card logic
โโโ test_asset_importer.py # CSV asset import + storage persistence
โโโ test_asset_correlation.py # CVE โ asset matching heuristic
โโโ test_log_parsers.py # Zeek, Suricata, Sysmon, generic JSONL parsers
โโโ test_exporters.py # Splunk/Elastic/Sentinel exporters โ mocked HTTP
โโโ test_evidence_pack.py # Evidence pack ZIP + manifest integrity
โโโ test_cli_e2e.py # Full CLI run against real NVD API (opt-in, --run-e2e)
Design principles
- Pluggable enrichers โ adding a new intel source only requires a new file in
src/enrichers/that subclassesBaseEnricher. No changes needed elsewhere. - Typed IOCs โ IOC types are enums, not raw strings, catching mistakes at development time instead of runtime.
- Safe HTTP client โ
BaseEnricher.get()enforces HTTPS-only, host allow-listing, redirect blocking, 429/Retry-After handling, and request budget capping in one place. - CI/CD-friendly config โ keys are read from
config/keys.envwith a fallback to system environment variables. - Per-enricher rate limiting โ configurable delay (
--delay) keeps you within each API's free-tier limits. - Fault isolation โ every enricher error is caught, logged, and stored in
result.errors; a single failing API never brings down the whole scan. - Spreadsheet safety โ all values written to Excel and CSV are neutralised against formula-injection (
=,+,-,@prefixes).
| Provider | Sign Up | Free Tier |
|---|---|---|
| AbuseIPDB | Free | 1,000 checks/day |
| VirusTotal | Free | 4 req/min ยท 500 req/day |
| AlienVault OTX | Free | Unlimited (public feed) |
| Shodan | Free | Limited lookups |
| URLScan.io | Free | 5,000 req/day (search is free) |
| NVD / NIST | Optional | No key required |
| CISA KEV | Not needed | Free, no key |
| FIRST.org EPSS | Not needed | Free, no key |
SIEM export destinations (also read from config/keys.env, all optional and opt-in via --export): SPLUNK_HEC_URL / SPLUNK_HEC_TOKEN, ELASTIC_URL / ELASTIC_API_KEY, and SENTINEL_TENANT_ID / SENTINEL_CLIENT_ID / SENTINEL_CLIENT_SECRET / SENTINEL_DCE_ENDPOINT / SENTINEL_DCR_IMMUTABLE_ID / SENTINEL_STREAM_NAME.
# Run all unit and integration tests (no network required)
pytest tests/ -v --ignore=tests/test_cli_e2e.py
# With coverage report
pytest tests/ -v --ignore=tests/test_cli_e2e.py --cov=src --cov-report=term-missing
# Run the end-to-end CLI test (makes a real NVD request)
pytest tests/test_cli_e2e.py --run-e2e -v| Test file | Coverage |
|---|---|
test_core.py |
IOC parser (all types + edge cases), verdict logic, SQLite cache round-trip |
test_enrichers.py |
BaseEnricher.get() โ redirect blocking, budget exhaustion, 429+Retry-After, API-key redaction in logs, non-JSON response, invalid JSON, host allow-list, HTTP scheme block |
test_reporters.py |
Excel & CSV formula-injection neutralisation (7 prefix variants), numeric passthrough, SQLite TTL expiry, upsert, investigation recording |
test_vuln_intel_enrichers.py |
CISA KEV feed caching/TTL, EPSS batch prefetching, missing/unexpected-field tolerance |
test_cve_decision.py |
Every Patch/Isolate/Monitor/Not-affected branch, the KEV hard-floor rule, and validation |
test_asset_importer.py |
Column validation, formula neutralisation, size/row DoS limits, storage persistence |
test_asset_correlation.py |
Product-token matching, criticality/exposure aggregation, "no product data" vs "not matched" |
test_log_parsers.py |
Zeek TSV, Suricata eve.json, Sysmon JSON, generic JSONL โ malformed-line tolerance, private-IP rejection |
test_exporters.py |
Splunk/Elastic/Sentinel โ mocked HTTP, allow-list enforcement, secret redaction, retry/backoff, dispatcher fault isolation |
test_evidence_pack.py |
ZIP contents, SHA-256 manifest integrity, secret redaction in packaged data |
test_cli_e2e.py |
Full subprocess run: python main.py -c CVE-2021-44228 --apis nvd --format json โ exit 0, valid JSON, correct verdict |
| Control | Implementation |
|---|---|
| HTTPS-only | BaseEnricher.get() / BaseExporter._post() reject any non-https:// URL before making a request |
| Host allow-list | Each enricher/exporter declares allowed_hosts; requests to unknown hosts are silently dropped |
| Redirect blocking | All requests use allow_redirects=False |
| 429 / Retry-After | Single automatic retry respecting the Retry-After header (capped at 15 s); exporters retry with capped exponential backoff |
| Request budget | --max-requests hard-caps total API calls per run |
| API-key / secret redaction | Exceptions and log lines have raw key/token values replaced with [REDACTED], including in exporter error paths and evidence packs |
| Formula injection | All Excel/CSV cell values (including imported asset data) are sanitised with spreadsheet_value() |
| IOC validation | Every CLI-, log-, and CSV-supplied IOC/value is validated and normalised before use |
| Private IP guard | Private/loopback addresses are rejected by default (--allow-private-iocs to override) |
| CSV/log parsing | csv.DictReader and json.loads only โ no eval/exec/pickle; streamed line-by-line with configurable file-size/row/line caps |
| TLS verification | Always on for SIEM export unless explicitly disabled with --export-insecure-tls, which logs a loud warning |
| Deterministic decisions | CVE Decision Cards are an explicit rule table, not an LLM call or opaque score, so every recommendation is auditable |
| Chain of custody | Evidence packs record a SHA-256 hash of every packaged file in manifest.json |
| Dependency audit | pip-audit runs in CI; requirements.lock pins all hashes for reproducible installs |
Terminal:
โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโ IOC Collection โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ Found 4 IOCs to investigate โ
โ CVE: 1 Domain: 1 Hash: 1 IP: 1 โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
โ Active APIs: abuseipdb, virustotal, otx, shodan, urlscan, nvd
๐ IP Address Results
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโ
โ IP Address โ Verdict โ Abuse % โ Country โ ISP / Org โ
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโค
โ 45.33.32.156 โ Suspicious โ 42 โ US โ Linode โ
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโ
โ ๏ธ CVE Results
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโฌโโโโโโโโโโโโโโโ
โ CVE ID โ Severity โ CVSS โ Published โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโผโโโโโโโโโโโโโโโค
โ CVE-2021-44228 โ Critical โ 10.0 โ 2021-12-10 โ
โโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโดโโโโโโโโโโโโโโโ
Excel Report: Multi-sheet workbook with color-coded verdicts (๐ด malicious ยท ๐ก suspicious ยท ๐ข clean), saved to output/ThreatLens_Report_<timestamp>.xlsx
- Local SQLite cache with TTL
- Per-run request budget
- IOC validation & private-IP guard
- Spreadsheet formula-injection protection
- API-key redaction in logs
- Pinned lockfile with SHA-256 hashes
- CI pipeline (GitHub Actions)
- Async/parallel enrichment for faster multi-IOC scans
- Optional Docker image
- STIX/TAXII export format
- Web dashboard (read-only) for report browsing
- Additional enrichers (GreyNoise, IPQualityScore)
Have an idea? Open an issue โ contributions and suggestions are welcome.
Contributions are welcome and appreciated!
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Add tests for any new behavior
- Make sure
pytest tests/ -v --ignore=tests/test_cli_e2e.pypasses andruff check .is clean - Open a pull request with a clear description of the change
New enrichers, bug fixes, documentation improvements, and test coverage are all great first contributions โ see Architecture for how enrichers are structured.
This project is licensed under the PolyForm Noncommercial License 1.0.0.
You're free to use, study, modify, and share this code for personal, educational, or research purposes. Commercial use is not permitted without prior written permission from the author (Abd.moh9999@yahoo.com).
This tool is intended for educational and authorized security testing purposes only. The user is solely responsible for complying with the terms of service of the integrated APIs and all applicable laws. The author assumes no liability and is not responsible for any misuse, illegal activity, or damage caused by this program.
If ThreatLens saved you time, consider giving it a โญ โ it helps others discover the project.





