Cybersecurity

How to Extract IOCs from Text?

Learn practical methods for extracting indicators of compromise from logs, threat reports, and security data to streamline your threat hunting workflow.

By Inventive HQ Team

Extracting IOCs from text, in one pass

Extracting indicators of compromise (IOCs) from text means running the raw report or logs through a pattern-matching pass — one regular expression per indicator type (IP addresses, domains, URLs, file hashes, emails) — then refanging the matches (turning hxxp back into http and [.] back into a dot), normalizing and deduplicating them, and exporting to CSV, JSON, or STIX. Purpose-built tools such as the Python library iocextract, the Go binary Cacador, or a browser-based IOC extractor do all of these steps in a single pass, so you rarely hand-write the regex or the refanging logic yourself.

That is the summary an AI overview gives you. What it can't give you is the part that actually decides whether your indicator list is usable: the regex that matches a defanged evil[.]com as readily as a live one, the refanging table that reverses each obfuscation, and the reason extraction has to be loose while validation is strict. This post is about extraction — pulling candidates out of the text. Confirming they are real and worth keeping is a separate job covered in the companion guide on validating extracted IOCs, and the full catalogue of what a good extractor recognizes lives in what IOC formats are supported.

Loading interactive tool...

The extraction pipeline

Every IOC extractor — whether it is fifteen lines of Python or an enterprise SIEM parser — runs the same five stages. The order matters: refang before you dedupe, because hxxp://evil[.]com and http://evil.com are the same indicator and should collapse into one row.

The five-stage IOC extraction pipeline Paste report or logs, then regex and parse per IOC type, then refang defanged forms, then normalize and deduplicate, then export to CSV, JSON, or STIX. A token travels left to right through the five stages. From raw text to a clean indicator list 1. Paste report / logs / threat intel 2. Regex + parse one pattern per IOC type 3. Refang hxxp to http [.] to . 4. Normalize lowercase + deduplicate 5. Export CSV / JSON / STIX

Extract loosely (steps 1-3), then normalize and validate strictly before you act.

The single most common mistake is skipping stage 3. Threat reports almost never contain live indicators — publishers defang them on purpose so a reader cannot fat-finger a click onto a live command-and-control server. A regex that only matches http:// and literal dots will silently miss the majority of the indicators in a well-written report.

IOC types, patterns, and defanged forms

The table below is the working core of any extractor: each indicator type, a regex that matches it, and the defanged forms you must refang before or during the match. Treat the patterns as extraction patterns — deliberately permissive to maximize recall. Tightening them into valid indicators is the job of the validation stage.

IOC typeExtraction regex (illustrative)Common defanged forms to refang
IPv4\b(?:\d{1,3}\.){3}\d{1,3}\b8[.]8[.]8[.]8, 8(.)8(.)8(.)8, 8[dot]8[dot]8[dot]8
IPv6\b(?:[A-Fa-f0-9]{1,4}:){2,7}[A-Fa-f0-9]{1,4}\bcolons occasionally wrapped as [:]
Domain\b(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}\bevil[.]com, evil(.)com, evil[dot]com
URL`\b(?:https?hxxps?
Email\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\buser[@]evil[.]com, user AT evil DOT com
MD5\b[a-fA-F0-9]{32}\brarely defanged; watch git short-hash collisions
SHA1\b[a-fA-F0-9]{40}\brarely defanged; overlaps git commit hashes
SHA256\b[a-fA-F0-9]{64}\brarely defanged
CVE\bCVE-\d{4}-\d{4,7}\boccasionally CVE‑ with a non-ASCII hyphen
Windows path`\b[A-Za-z]:\(?:[^\/:*?"<>\r\n]+\?)+`
Registry key`\bHK(?:LMCU

A few things the patterns above deliberately do not do, because they belong to validation rather than extraction:

  • Range-check IPv4 octets. \b(?:\d{1,3}\.){3}\d{1,3}\b will match 999.1.1.1. Extract it; let validation drop it.
  • Distinguish MD5 from a truncated SHA. Anchor on \b word boundaries so a 64-character SHA256 is not chopped into a bogus 32-character MD5.
  • Verify the TLD is real. A domain regex matches thing.local and file.exe; a validation pass compares the top-level domain against the IANA list.
Advertisement

Refanging: the step everyone forgets

Refanging is the inverse of URL defanging, and it is where a naive grep pipeline falls apart. There is no single standard for how analysts defang, so an extractor has to reverse a family of conventions. The reliable substitutions:

  • hxxphttp, hxxpshttps, fxpftp
  • [.], (.), {.}, [dot], (dot), dot.
  • [:], [://]: / ://
  • [@], (at), at@
  • Leading/trailing angle brackets and backticks stripped from URLs

The Python library iocextract handles all of these for you and exposes a refang=True flag so extraction and refanging happen in one call. If you are scripting it, the pattern is short:

import iocextract

with open("report.txt") as f:
    text = f.read()

urls   = list(iocextract.extract_urls(text, refang=True))
ips    = list(iocextract.extract_ips(text, refang=True))
hashes = list(iocextract.extract_hashes(text))
emails = list(iocextract.extract_emails(text, refang=True))

Choosing an extraction tool

You do not need to reinvent the regex table above — several mature tools already encode it, including the defanged forms.

ToolFormBest for
Browser IOC extractorPaste-and-go web toolAd-hoc jobs, no install, quick triage of a single report
iocextractPython library + CLI (pip install iocextract)Scripting, pipelines, embedding in Python tooling
CacadorSingle Go binary, reads stdin, emits JSONFast command-line one-liners, runtimes without Python
SIEM parsers (Splunk, Elastic)Ingest-time field extractionContinuous extraction from live log streams at scale
Custom regex + grepYour own scriptsFull control, learning, one-off spot checks

For a report you have pasted into a browser, the fastest route is a web extractor that runs entirely client-side — no upload, no round trip.

Loading interactive tool...

When to reach for each: use a browser tool for a one-off paste; reach for iocextract when the job is part of a Python workflow or you want to chain it into enrichment; pick Cacador for a shell one-liner (cat report.txt | cacador) or a container without a Python runtime; and lean on your SIEM's field extraction when the source is a continuous log stream rather than a static document.

Extract loosely, validate strictly

The guiding principle across every stage above: extraction should maximize recall and validation should maximize precision. Extract with permissive patterns so no indicator hides behind a defanged dot or an unusual encoding, refang everything, then hand the raw candidate list to a strict validation pass that range-checks octets, confirms hash lengths, checks TLDs against IANA, and filters your internal allowlist. Collapsing those two stages into one over-tight regex is how real indicators get silently dropped.

Handling special cases

Real-world text throws edge cases at every extractor:

  • Split indicators. URLs wrapped across a line break or a domain broken by a stray space. Some extractors reassemble these; grep will not.
  • False positives by shape. Version numbers look like IPv4, git commit hashes look like SHA1, CDN and telemetry domains look malicious, and standard Windows paths look like malware artifacts. Extraction over-collects by design — filtering happens later.
  • Mixed encodings. UTF-8 versus ASCII, and non-ASCII look-alike characters (a Cyrillic а inside a domain, or a Unicode hyphen inside a CVE ID). Normalize encoding before matching.
  • Deduplication with case. EVIL.COM and evil.com are one domain. Lowercase domains and emails during normalization so dedupe actually collapses them.

Integrating extraction into your workflow

Extracted indicators only create value once they flow into operations. Export the deduplicated set as STIX or CSV into your threat intelligence platform, push high-confidence indicators into SIEM watchlists or firewall blocklists, and keep a note of each indicator's source document so you can retrace provenance during an investigation. Establish a retention and review cycle — stale indicators clutter detection logic and drive false positives as infrastructure gets reused by unrelated parties.

Conclusion

Extracting IOCs from text is a five-stage pipeline — paste, regex-parse per type, refang, normalize and dedupe, export — and the stages that separate a usable indicator list from a noisy one are refanging and the extract-loose-then-validate-strict discipline. Whether you paste a report into a browser extractor, script iocextract into a Python pipeline, or pipe text through Cacador, the mechanics are the same. Get the candidates out completely first; then move to validating what you extracted to decide what is actually worth acting on.

Frequently Asked Questions

How do you extract IOCs from text?

Run the text through a pattern-matching pass, one regular expression per indicator type — IPv4/IPv6, domains, URLs, MD5/SHA1/SHA256 hashes, and email addresses. Then refang the results (turn hxxp back into http and [.] back into a real dot), normalize them (lowercase domains, strip trailing punctuation), remove duplicates, and export to CSV, JSON, or STIX. Dedicated tools like the Python library iocextract, the Go tool Cacador, or a browser-based IOC extractor do all five steps in one pass so you do not have to hand-write the regex or the refanging logic.

What is refanging and why does IOC extraction need it?

Refanging is reversing defanging — the deliberate mangling analysts apply to indicators so they cannot be accidentally clicked or auto-linked. Defanged forms look like hxxp://evil[.]com or 8[.]8[.]8[.]8, with the scheme broken and the dots wrapped in brackets. Because threat reports are full of these, a naive regex that only matches http:// and real dots will miss most of the indicators in the document. Refanging converts hxxp/hxxps back to http/https, replaces [.] (.) and {.} with a plain dot, and turns [@] back into @ — so extraction and refanging almost always run together.

What regex extracts an IPv4 address?

A common pattern is \b(?:\d{1,3}.){3}\d{1,3}\b, which matches four dot-separated groups of one to three digits. It matches the shape of an IPv4 address but not its validity — it will happily match 999.999.999.999 or a version string like 1.2.3.4. That is why extraction is only step one: a validation pass afterward checks that every octet is 0-255 and drops private, reserved, or obviously bogus ranges. Extract loosely, then validate strictly.

How do you tell MD5, SHA1, and SHA256 hashes apart?

By length. A hash is a run of hexadecimal characters (0-9 and a-f), and the length identifies the algorithm: 32 characters is MD5, 40 is SHA1, and 64 is SHA256. A single regex, \b[a-fA-F0-9]{32,64}\b, catches all three, and you classify each match by counting its characters. Anchor the pattern on word boundaries so a 64-character hash is not sliced into a false 32-character MD5.

What is the difference between iocextract and Cacador?

Both extract and refang indicators, but they suit different workflows. iocextract is a Python library and CLI (pip install iocextract) that shines when you want to script extraction, pipe results into other Python tooling, or embed it in a pipeline. Cacador is a single self-contained Go binary that reads from stdin and emits JSON, which makes it ideal for fast command-line one-liners and environments where you would rather not manage a Python runtime. For an ad-hoc paste-and-go job with no install, a browser-based extractor is faster than either.

Why do extraction tools produce false positives?

Because many benign strings share an IOC's shape. Version numbers (1.2.3.4) look like IP addresses, git commit hashes look like SHA1, CDN and Microsoft telemetry domains look like malicious domains, and standard Windows paths look like malware artifacts. Extraction matches the pattern, not the meaning, so it over-collects by design. Filtering (allowlists of internal ranges and trusted domains) and a separate validation stage are what turn a noisy raw match list into an actionable indicator set.

Can you extract IOCs without any tools?

Yes, for small samples. Grep with a regex per type will pull indicators out of a log file, and a spreadsheet handles deduplication for a handful of results. The approach breaks down at scale and, more importantly, misses defanged indicators unless you also script the refanging — which is most of the value a purpose-built tool adds. Manual extraction is best kept as a way to spot-check and understand what an automated tool is doing, not as the primary workflow.

What formats can extracted IOCs be exported to?

The common targets are CSV (for spreadsheets and quick review), JSON (for scripts and APIs), and STIX (the structured threat-intelligence standard that TIPs and sharing communities consume). Many teams also push indicators straight into a threat intelligence platform or a SIEM watchlist. Whatever the format, export after normalizing and deduplicating so the same indicator is not represented three different ways downstream.

Is extracting IOCs the same as validating them?

No — they are two separate stages. Extraction pulls candidate indicators out of unstructured text using pattern matching and refanging; it is deliberately loose so nothing is missed. Validation then confirms each candidate is well-formed and worth keeping — checking octet ranges, hash lengths, valid TLDs, and filtering allowlisted or defanged-only artifacts. Extract first to maximize recall, then validate to maximize precision.

IOC extractionthreat huntingindicators of compromisesecurity analysis