open source · pip install iocflow

iocflow

The whole IOC lifecycle — extract, enrich, hunt, block — as deterministic tools, with an agent on top that never gets the final say on a destructive action.

Six pip-installable layers for indicators of compromise. The boring primitives do the irreversible work the same way every time; a small LangGraph team orchestrates them; and a human stands between the AI and anything that touches production.

$pip install iocflowclick to copy See the authority model ↓ View source
scroll
0
layers
extract · enrich · comment · hunt · block · agent — each its own pip extra, each useful on its own.
0
import
investigate(text) runs the whole chain as a multi-agent team.
0
rogue blocks
the LLM proposes, a human authorizes, and a dumb guard vetoes anything on the allowlist.
the failure mode in agentic security tooling

An LLM with a block() tool is one hallucination away from production.

Give an agent autonomy over irreversible actions — push a firewall denylist, isolate a host — and a single confidently-wrong indicator becomes a self-inflicted outage.

Indicator under review
8.8.8.8 — seen in outbound traffic from a flagged host
Agent, ungated
Identified 8.8.8.8 as C2 infrastructure. Pushing to the firewall denylist now. ✅
⚠ 8.8.8.8 is Google Public DNS. The model pattern-matched "suspicious outbound IP" and reached straight for the block tool — no allowlist check, no human. That's an outage, authored by an AI.

The fix isn't a smarter model. It's structural: the model proposes and never executes, and no single authority can push a destructive change on its own.

the centerpiece · interactive

The model proposes. A human authorizes. A guard vetoes.

Pick an indicator and walk it through the lifecycle. Watch where the benign one gets stopped — before the agent can ever propose it.

1 · choose an indicator from the report
L1
Extract
L2 · L3
Enrich
L6
Propose
L5
Block
2 · three-layer authority — no single one can act alone
🤖
LLM proposes
🧑
Human authorizes
🛡️
Guard vetoes
deterministic primitives first, agents last

Six layers. The model orchestrates; it doesn't do.

Each layer is a plain, testable function behind its own pip extra — so import iocflow stays a one-dependency install and pulls in nothing you didn't ask for.

L1

extract

iocflow

Pull IPs, domains, URLs, hashes, CVEs, ATT&CK technique IDs, threat actors and malware families out of unstructured text — with Public Suffix List validation, benign allowlists and re-fanging of evil-domain[.]ru built in.

L2

enrich

iocflow[enrich]

Look each indicator up against VirusTotal, AbuseIPDB and abuse.ch, and return a single worst-wins verdict.

L3

comment

iocflow[ai]

An LLM turns the enrichment into a structured assessment — and falls back to a deterministic, report-derived summary when no model is configured. It never raises.

L4

hunt

iocflow[hunt]

Render ready-to-run hunt queries — CrowdStrike CQL, Cortex XQL and Sigma — straight from the indicators, offline and stdlib-only. An LLM can add behavioral hunts; the deterministic ones are always there.

L5

block

iocflow[block]

Push malicious indicators to the control points you operate — Palo Alto, Zscaler, CrowdStrike, Abnormal — with dry_run=True as the default everywhere and an authoritative allowlist guard underneath.

L6

agent

iocflow[agent]

The capstone: a small LangGraph team that uses L1–L5 as tools and loops until the case is done.

L1–L5 don't know the agent exists. They're plain functions with stable types — ExtractedEntities → EnrichmentReport → Commentary → HuntPlan → BlockReport — so you can use any one alone. The agent is a consumer of the primitives, not a replacement for them.

supervisorroutes the next step
extractorL1 entities
enricherL2 · L3 verdict
hunterL4 queries
responderL5 · proposes only
each specialist returns to the supervisor → the loop continues until the case is done, and the responder can only ever propose.
bring your own model · one import

The whole chain in a line — or any layer on its own.

Inject any chat model as a plain callable. The core has zero third-party dependencies; the heavy integrations ride on opt-in extras, lazily imported.

quickstart.py
from iocflow import investigate

# one call: extract → enrich → comment → hunt → propose → (human) → block
report = investigate(report_text)              # the multi-agent team, end-to-end

# or use any layer on its own — they're just typed functions
from iocflow import extract, enrich, suggest_hunts
iocs    = extract(report_text)                 # deterministic, FP-defended
verdict = enrich(iocs)                        # worst-wins across feeds
hunts   = suggest_hunts(iocs)                 # CQL · XQL · Sigma, offline

# blocking is dry-run by default, behind an allowlist guard
block(verdict.malicious, dry_run=True)       # renders the calls; changes nothing
pip install iocflow [enrich] VT · AbuseIPDB · abuse.ch [ai] LLM commentary [hunt] CQL · XQL · Sigma [block] PAN · Zscaler · CrowdStrike [agent] the LangGraph team [all] everything
where it came from

Distilled from a production AI SOC.

iocflow is the open-source sibling of SOC-in-a-Box — an AVP-sponsored multi-agent SOC where one local LLM played eight analyst roles, read-only against production, with a human approving every containment action.

SOC-in-a-Box proved the pattern against real systems. Two commitments made it trustworthy: the model orchestrates but never does the irreversible work itself, and no single authority can push a destructive action. Those ideas aren't SOC-specific — they're how you make any AI system that touches production safe enough to deploy. So I pulled them out and built a clean, public library around them.

the LLM proposes · a human authorizes · a guard vetoes

pip install iocflow

$pip install iocflowclick to copy
copied ✓