# Threat Intel Toolkit

> Draft · awaiting review.

> Claude Code plugin with a subagent and two skills that triage IOCs and CVEs against free threat-intel feeds, without API keys.

- Badge: `reach ≥2 · not run yet`
- Type: Plugin; tier: not run yet
- Tasks: Threat intel enrichment, Vulnerability prioritization; mission: Defensive; works with: Claude Code
- Source: https://github.com/kevinmhorvath/threat-intel-toolkit, pinned to `8b5acb2`, licence MIT
- Last checked: 2026-10-21; next check: 2027-01-19; method v0.1, reach-v0.1

## At a glance

- **What it is:** Threat Intel Toolkit is a Claude Code plugin with a subagent and two skills for defensive IOC and vulnerability triage on free open-source threat feeds that need no API keys. A plugin bundles skills, commands, hooks or MCP servers for one AI client.
- **Made for:** Answer whether any reputable free feed flags an indicator, and how strongly, as a defensive triage aid. +2 more
- **Runs:** On your machine, started by your AI client. Other modes: direct CLI (on your machine, started by you); no-shell fallback (inside your AI client: its model follows the instructions and works with the client's own tools).
- **Sends data to:** CISA KEV and abuse.ch Feodo Tracker (by default), blocklist.de and stamparm/ipsum (by default), Emerging Threats and GreenSnow (by default), Tor Project and SANS DShield (by default), Spamhaus and Phishing.Database (by default), FIRST EPSS (api.first.org) (by default), cisa.gov, GitHub and GitLab (by default), nomi-sec and trickest PoC indexes (by default), Client web search (if you turn it on). Other connections not ruled out: read in the documentation and the cited code, not searched in full.
- **Can change things:** Changes, runs commands, according to the capabilities read.
- **Needs:** Needs Python 3.8 or later; the scripts use the standard library and need no pip installs · Installs as a plugin from the repository's own single-plugin marketplace (.claude-plugin/marketplace.json and .claude-plugin/plugin.json) · ti.py needs network access to each feed URL to build its cache; each download uses urllib with a 90-second timeout · +2 more

Profile read at commit `8b5acb2` on 2026-10-25; every fact cites a file and line at that commit.

## What it does

Threat Intel Toolkit is a Claude Code plugin with a subagent and two skills for defensive IOC and vulnerability triage on free open-source threat feeds that need no API keys. (.claude-plugin/plugin.json#L4)

Made for (the author says):

- Answer whether any reputable free feed flags an indicator, and how strongly, as a defensive triage aid. (skills/threat-intel-lookup/SKILL.md#L18)
- Rate how ready-made the public exploit material for a CVE is, so defenders and pentesters can prioritize. (skills/exploit-availability-check/SKILL.md#L8)
- Build or refresh a local blocklist from free, key-free open-source feeds. (agents/threat-intel-analyst.md#L7)

Documented uses:

- Enrich a batch of IOCs pasted from a SIEM alert, firewall log, phishing email or incident timeline. [Threat intel enrichment] (agents/threat-intel-analyst.md#L8)
- Rate exploit maturity and in-the-wild status of CVEs during vulnerability triage, patch prioritization or pentest scoping. [Vulnerability prioritization] (skills/exploit-availability-check/SKILL.md#L3)
- Check a URL from a suspicious email, where a hit on the phishing-domain feed carries the most weight. [Email and phishing analysis] (skills/threat-intel-lookup/SKILL.md#L80)
- Write a Markdown and CSV report of indicator verdicts for a ticket, IR timeline or client folder. [Alert triage] (skills/threat-intel-lookup/SKILL.md#L88)

Not for (the author says):

- Meant for defensive prioritization; the author states it never contacts, scans or attacks an indicator. (README.md#L116-117)
- Does not write new exploit code, weaponize a PoC or give exploitation steps; it locates and rates already-public material. (skills/exploit-availability-check/SKILL.md#L85)
- File hashes are out of scope, because the free hash feeds the author considered require an API key. (README.md#L28)

## What it can do

| Group | What it covers | Effect | On by default |
|---|---|---|---|
| ti.py aggregate | ti.py aggregate downloads and normalizes the registry feeds into the local cache; --refresh forces re-download, --only and --exclude select feeds by key. (skills/threat-intel-lookup/scripts/ti.py#L582-587) | reads, changes | yes |
| ti.py lookup | ti.py lookup checks IPs, domains, URLs and CVEs (defanged accepted) against the cache; --json prints machine-readable output and --report writes Markdown and CSV files to --out. (skills/threat-intel-lookup/scripts/ti.py#L589-594) | reads, changes | yes |
| ti.py feeds | ti.py feeds lists the curated feed registry. (skills/threat-intel-lookup/scripts/ti.py#L579) | reads | yes |
| exploit-availability-check | exploit_check.py reports in-the-wild status and a public exploit maturity tier per CVE from CISA KEV, FIRST EPSS, Metasploit, Nuclei, Exploit-DB, nomi-sec and trickest. (skills/exploit-availability-check/scripts/exploit_check.py#L5-13) | reads, changes | yes |
| threat-intel-analyst | The threat-intel-analyst subagent is granted the Bash, Read, Write, Glob and Grep tools. (agents/threat-intel-analyst.md#L12) | reads, changes, runs commands | yes |
| healthcheck.py | One healthcheck.py per skill: the lookup one fetches and parses all 10 feeds; the exploit one checks that every source returns a known canary CVE (Log4Shell). (README.md#L100-106) | reads | no |
| Fallback (no shell) | Without a shell, the exploit skill tells the model to fetch EPSS, nomi-sec, trickest and Nuclei per CVE with its fetch tool and to WebSearch KEV, Metasploit and Exploit-DB. (skills/exploit-availability-check/SKILL.md#L52) | reads | no |

## How it runs

A subagent routes indicators to two skills: threat-intel-lookup, whose stdlib-only script ti.py aggregates 10 free feeds into a local SQLite cache and looks indicators up in it, and exploit-availability-check, which rates a CVE via KEV, EPSS, Metasploit, Nuclei, Exploit-DB and PoC aggregators. (README.md#L7-15)

- Starts: On your machine, started by your AI client. The exploit skill has the client's model run the bundled script scripts/exploit_check.py with the CVE IDs as a local process. (skills/exploit-availability-check/SKILL.md#L36)
- Can also run: On your machine, started by you (direct CLI). The user can run ti.py feeds, aggregate and lookup directly from a shell in skills/threat-intel-lookup/scripts. (README.md#L57-61)
- Can also run: Inside your AI client: its model follows the instructions and works with the client's own tools (no-shell fallback). Without a shell, the lookup skill tells the client's model to fetch a single feed with its web tool and search it. (skills/threat-intel-lookup/SKILL.md#L92)
- Your AI client: **threat-intel-analyst subagent**: Subagent definition named threat-intel-analyst. (agents/threat-intel-analyst.md#L2)
- Your AI client: **Skills (SKILL.md)**: The threat-intel-lookup and exploit-availability-check skills, usable directly or orchestrated by the subagent. (README.md#L17-19)
- Your machine: **ti.py**: Stdlib-only Python engine; keeps raw feed bodies under ~/.cache/ti-aggregator/raw with a TTL and the parsed data in ~/.cache/ti-aggregator/ti.db. (skills/threat-intel-lookup/scripts/ti.py#L27-31)
- Your machine: **exploit_check.py**: Python script that caches KEV, Metasploit, Nuclei and Exploit-DB locally and fetches EPSS, nomi-sec and trickest data live per CVE. (skills/exploit-availability-check/scripts/exploit_check.py#L15-17)
- Outside your machine: **Indicator feeds**: Ten public feeds, among them CISA KEV, abuse.ch Feodo Tracker, Spamhaus DROP and Phishing.Database, supply indicator and CVE data. (README.md#L23-25)
- Outside your machine: **Exploit sources**: CISA KEV, FIRST EPSS, Metasploit, Nuclei, Exploit-DB, nomi-sec and trickest supply exploit and in-the-wild data per CVE. (skills/exploit-availability-check/SKILL.md#L14-22)
- Sends data to CISA KEV and abuse.ch Feodo Tracker (download, by default): ti.py downloads the CISA Known Exploited Vulnerabilities JSON and the abuse.ch Feodo Tracker IP blocklist during aggregate. (skills/threat-intel-lookup/scripts/ti.py#L64-72)
- Sends data to blocklist.de and stamparm/ipsum (download, by default): ti.py downloads the blocklist.de list and the stamparm/ipsum level 3 list from raw.githubusercontent.com during aggregate. (skills/threat-intel-lookup/scripts/ti.py#L73-80)
- Sends data to Emerging Threats and GreenSnow (download, by default): ti.py downloads the Emerging Threats compromised-IP list and the GreenSnow list during aggregate. (skills/threat-intel-lookup/scripts/ti.py#L81-88)
- Sends data to Tor Project and SANS DShield (download, by default): ti.py downloads the Tor Project exit list and the SANS DShield block list during aggregate. (skills/threat-intel-lookup/scripts/ti.py#L89-97)
- Sends data to Spamhaus and Phishing.Database (download, by default): ti.py downloads Spamhaus DROP netblocks and the Phishing.Database active phishing domains during aggregate. (skills/threat-intel-lookup/scripts/ti.py#L98-106)
- Sends data to FIRST EPSS (api.first.org) (vendor API, by default): exploit_check.py sends each CVE ID to the FIRST EPSS API and reads the exploitation probability. (skills/exploit-availability-check/scripts/exploit_check.py#L150-153)
- Sends data to cisa.gov, GitHub and GitLab (download, by default): exploit_check.py downloads KEV from cisa.gov, Metasploit and Nuclei indexes from GitHub, and the Exploit-DB CSV from GitLab. (skills/exploit-availability-check/scripts/exploit_check.py#L33-38)
- Sends data to nomi-sec and trickest PoC indexes (download, by default): exploit_check.py fetches nomi-sec and trickest PoC index files live for each CVE it assesses. (skills/exploit-availability-check/scripts/exploit_check.py#L16-17)
- Sends data to Client web search (other, if you turn it on): For a vulnerability given by name, the exploit skill has the model run a WebSearch for the name plus CVE to find its CVE IDs. (skills/exploit-availability-check/SKILL.md#L31)

## What you need

- Runtime: Needs Python 3.8 or later; the scripts use the standard library and need no pip installs. (README.md#L70)
- Runtime: Installs as a plugin from the repository's own single-plugin marketplace (.claude-plugin/marketplace.json and .claude-plugin/plugin.json). (README.md#L80-81)
- Other: ti.py needs network access to each feed URL to build its cache; each download uses urllib with a 90-second timeout. (skills/threat-intel-lookup/scripts/ti.py#L181-184)
- Other: The first exploit check downloads about 35 MB of feeds into ~/.cache/exploit-availability-check, kept for 24 hours. (skills/exploit-availability-check/SKILL.md#L36)
- Other: Indicator lookups need a cache built first with ti.py aggregate, about 13 seconds for about 435k indicators. (agents/threat-intel-analyst.md#L45-48)
- Installer: Two Claude Code commands add the GitHub repository as the marketplace threat-intel-marketplace and install the threat-intel-toolkit plugin; the commands name no tag or commit. (README.md#L83-86)
- Installer: The README also mentions sharing the folder as a zip file or installing a skill on its own. (README.md#L89-90)
- Installer: The author also keeps a standalone exploit-availability-check skill; since 1.1.0 its exploit_check.py is byte-identical to the copy bundled in this toolkit. (CHANGELOG.md#L22-23)

## Limits and risks

- Indicator lookups read the local cache at ~/.cache/ti-aggregator/ti.db and do not go to the network. (skills/threat-intel-lookup/SKILL.md#L47)
- The subagent is granted Bash, Read, Write, Glob and Grep; its description asks the host to use it proactively when the user drops an IP, domain, URL or CVE, even without the words threat intel. (agents/threat-intel-analyst.md#L4-12)
- The author states that a CLEAN verdict is never a safety guarantee. (README.md#L117)
- blocklist.de and GreenSnow are in the default feed set but publish no formal licence; the README shows how to exclude them. (README.md#L50-52)
- Before 1.1.0, when a source such as CISA KEV was unreachable and no local cache existed, exploit-availability-check reported it as not listed; since 1.1.0 such sources show as unknown. (CHANGELOG.md#L10-18)
- The exploit skill tells the model to flag low-star GitHub PoC repos as possibly non-functional or malicious. (skills/exploit-availability-check/SKILL.md#L86)
- exploit_check.py does not query Packet Storm, CXSecurity or 0day.today, which the author says have no open data feed. (skills/exploit-availability-check/SKILL.md#L24)
- exploit_check.py takes every command-line argument that starts with CVE- as a CVE ID to assess. (skills/exploit-availability-check/scripts/exploit_check.py#L418)
- The threat-intel-lookup skill triggers on its own whenever the user drops an IOC into the conversation. (README.md#L12)
- When a feed download fails, ti.py reuses the previously cached copy of that feed and notes this on stderr. (skills/threat-intel-lookup/scripts/ti.py#L189-193)
- ti.py defines the User-Agent threat-intel-lookup/1.0 (+defensive-ioc-triage) for its feed requests. (skills/threat-intel-lookup/scripts/ti.py#L55)
- ti.py rates an indicator MALICIOUS when three or more feeds list it, SUSPICIOUS when one or two do and CLEAN when none does; a hit only on the Tor exit list gives CONTEXT and a CVE on CISA KEV gives EXPLOITED. (skills/threat-intel-lookup/scripts/ti.py#L401-410)

## Rights in plain language

- Declared: files 2 (writes outside the project), network 1 (talks only to declared hosts), execution 2 (runs shell commands or eval), secrets 0 (touches no credentials), persistence 1 (leaves cache or temp files).
- Code: reach ≥2 (open): files 2 (writes outside the project), execution 2 (runs shell commands or eval); unknown: secrets.
- Lab: not run yet.

Why three columns? Declarations are often incomplete and scanners can be bypassed, so we run each tool once and compare.

## Privilege Reach

Reach level 2 (open), one right unknown.

| Right | Declared | Code | Lab |
|---|---|---|---|
| Files: where does it read and write? | 2 writes outside the project | 2 writes outside the project | not run yet |
| Network: whom does it talk to? | 1 talks only to declared hosts | 1 talks only to declared hosts | not run yet |
| Execution: what does it run? | 2 runs shell commands or eval | 2 runs shell commands or eval | not run yet |
| Secrets: which credentials does it touch? | 0 touches no credentials | ? unknown | not run yet |
| Persistence: what survives the run? | 1 leaves cache or temp files | 1 leaves cache or temp files | not run yet |
| Approval: does it ask before acting? | not declared | 0 asks each time | not run yet |

0 contained · 1 scoped · 2 open · 3 privileged · ? no evidence · 0 never means safe

## Install

### Upstream

Quoted from `README.md#L84-85` at the pinned commit (not a command to copy): `/plugin marketplace add kevinmhorvath/threat-intel-toolkit
/plugin install threat-intel-toolkit@threat-intel-marketplace`


### Run it with least privilege

- claude code: `permissions.allow: [Read, Grep, Bash(python3 skills/*)]; keep other Bash calls and Write on ask, and pass --out with a case folder`
- note: `derived from the code, not tested in the lab`

- derived, not tested: proposed from the code analysis

## Lab runs

Not run yet.

## Questions and answers

**Why compare declared, code and lab?**

Declarations are often incomplete and scanners can be bypassed, so we run each tool once and compare.

**What rights does Threat Intel Toolkit declare?**

files 2 (writes outside the project), network 1 (talks only to declared hosts), execution 2 (runs shell commands or eval), secrets 0 (touches no credentials), persistence 1 (leaves cache or temp files).

**What does its code suggest?**

reach ≥2 (open): files 2 (writes outside the project), execution 2 (runs shell commands or eval); unknown: secrets.

**What did it use when it ran in the lab?**

not run yet.

**Was it tried, and when?**

Not yet (tier listed).

**What changed since the last check?**

Upstream last pushed 2026-08-18; 0 release(s) since the pinned version.

**How do I run it with least privilege?**

Derived, not tested: claude_code: permissions.allow: [Read, Grep, Bash(python3 skills/*)]; keep other Bash calls and Write on ask, and pass --out with a case folder; note: derived from the code, not tested in the lab

Method: https://readbeforerun.ai/method/
