threatpivot
Multi-source IOC enrichment and pivot tool for threat intelligence analysts. No Docker. No server.
pip install threatpivotand go.
Why threatpivot exists
Every CTI and SOC analyst knows the workflow: receive one suspicious domain, open eight browser tabs, copy-paste the IOC into each tool, manually combine the results, and write a verdict. It takes 10–15 minutes per IOC.
threatpivot does all of that in under 5 seconds from your terminal.
It is built for the individual analyst — not a team that can afford a shared
IntelOwl server. pip install, add your free API keys, and every IOC lookup
runs 8 sources in parallel with a weighted confidence verdict and a
finished report you can paste straight into a ticket.
Install
pip install threatpivot
Quickstart
# Single IOC — auto-detects type
pivot lookup evil-domain.com
pivot lookup 185.220.101.45
pivot lookup 44d88612fea8a8f36de82e1278abb02f
# Defanged IOCs work natively
pivot lookup 'login-microsoft[.]com'
pivot lookup 'hxxps://evil[.]com/payload.exe'
# Output formats
pivot lookup evil.com --output markdown
pivot lookup evil.com --output json
pivot lookup evil.com --output html --save report.html
pivot lookup evil.com --output stix --save bundle.json
# Bulk enrichment from file (one IOC per line)
pivot batch iocs.txt
pivot batch iocs.txt --output csv --save results.csv
# Campaign mode — group IOCs into an investigation
pivot campaign new "phishing-campaign-2024"
pivot campaign add "phishing-campaign-2024" evil.com
pivot campaign add "phishing-campaign-2024" 185.220.101.45
pivot campaign report "phishing-campaign-2024" --output html
# Configure API keys interactively
pivot configure
# See which sources are active
pivot providers
# Pipeline mode — exit code 1 if malicious
pivot lookup "$IOC" --fail-on-malicious
Sources
| Source | IOC Types | Key Required | Free Tier |
|---|---|---|---|
| VirusTotal | All | Yes | 500/day |
| AbuseIPDB | IP | Yes | 1,000/day |
| ThreatFox | All | Yes | Unlimited |
| urlscan.io | Domain, URL | No | Unlimited public |
| AlienVault OTX | All | Yes | Unlimited |
| Shodan | IP | Yes | Limited |
| GreyNoise | IP | Yes | Community tier |
| crt.sh | Domain | No | Unlimited |
| URLhaus | All | No | Unlimited |
All sources are free. There is no Pro tier. No paywalled providers.
How confidence scoring works
threatpivot does not simply count how many sources flagged an IOC.
Each source has a weight based on its reliability and signal strength:
| Source | Weight | Rationale |
|---|---|---|
| VirusTotal | 35% | 70+ AV engines, highest signal |
| ThreatFox | 25% | Community-verified C2 data |
| AbuseIPDB | 20% | Volume of abuse reports |
| OTX | 10% | Community quality varies |
| urlscan | 5% | Passive, lower confidence |
| Others | 5% | Context/pivot value |
Final verdict thresholds:
| Score | Verdict |
|---|---|
| ≥ 0.65 | MALICIOUS |
| ≥ 0.30 | SUSPICIOUS |
| > 0.00 | CLEAN |
| 0.00 | UNKNOWN |
Privacy & security
- Private and reserved IPs (RFC1918, loopback, link-local) are never sent to external APIs
- API keys are stored in
~/.config/threatpivot/config.tomland never appear in output, logs, or--jsonmode - All external requests use HTTPS with certificate verification
- Defanged inputs are validated before refanging to prevent injection
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success — verdict may be clean, suspicious, or unknown |
| 1 | --fail-on-malicious set and verdict was MALICIOUS |
| 2 | Bad input — unrecognised IOC type or config error |
| 3 | --fail-on-error set and at least one source returned no answer |
Use both flags together for a strict security gate:
pivot lookup "$IOC" --fail-on-malicious --fail-on-error
Adding a source
Every source is a self-contained class. Inherit BaseSource, implement
_query() and confidence_weight(), register in sources/__init__.py,
and open a PR. See CONTRIBUTING.md.
Contributing
Contributions welcome. Good first issues are tagged in the GitHub tracker. Sources we don't yet cover: MalwareBazaar, SecurityTrails, Censys.
License
MIT — see LICENSE.
Metadata
Release files for threatpivot 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| threatpivot-0.1.0.tar.gz | 67.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| threatpivot-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 142.1 kB
Release files / threatpivot-0.1.0.tar.gz
| Download URL | threatpivot-0.1.0.tar.gz |
|---|---|
| Size | 67.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
14ac830292dc28d15a1bfb1d1a386918b63acfecf2de2cb003de7a600f3f20dd
|
|
BLAKE2b-256 checksum How to use checksums |
89f6fc367859f5927937ec570fed13ad9878680af6e21069d53e7857cff9021c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|
Release files / threatpivot-0.1.0-py3-none-any.whl
| Download URL | threatpivot-0.1.0-py3-none-any.whl |
|---|---|
| Size | 75.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e1910dd99daa447e56981b60f71d2ab55c59fc5d18aead9e4585a01e6b816595
|
|
BLAKE2b-256 checksum How to use checksums |
8872f18e711068afad14e97ef97dfc2ffe48163a326ef56f115c57d7030dee97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|