NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Python package for finding and parsing indicators of compromise from text.
Last release 3 months ago
17 Jun 2026
Ships unpredictably
gaps range from 9 days to 3.2 years
Some releases are documented
notes for 28 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
9 years old
71 releases · first in 2018
Fixed quadratic-time (ReDoS) behavior in the email-address candidate prefilter. The old (?:local+)@domain candidate regex restarted and re-walked the
(?:local+)@domain candidate regex restarted and re-walked the local part at every offset, so a long run of local-part characters (e.g. a base64/hex blob) caused find_iocs to hang — two 100 KB blobs took ~16 minutes each. The prefilter now anchors on @ and expands outward in linear time (_email_candidate_spans), with the domain tail matched by an anchored .match(); the pyparsing email grammar remains the precise validator and detection results are unchanged (#389).ioc-fanger dependency floor to 5.1.1 (range >=5.1.1,<5.2).Support unicode parsing
Support unicode parsing
One column per quarter.
parse_unicode_iocs option to find_iocs (and a --parse_unicode_iocs CLI flag), default False (#298). When enabled, domain labels may contain non-ASCII (Unicode) characters — e.g. warrıors.com (note the dotless ı) is now parsed, as is the domain part of email, URL, and XMPP IOCs. The TLD itself stays ASCII (IANA stores internationalized TLDs in their xn-- punycode form), as do email/URL/XMPP local parts and URL paths. The ASCII and Unicode grammar variants are generated from a single builder (ioc_grammars._build_domain_layer) so they can't drift.New ioc types, bug fixes, and performance improvements
New ioc types, bug fixes, and performance improvements
domain_name grammar is still used as a sub-grammar inside email/url/xmpp parsers, where its inner label loop has been collapsed into a single Regex (replacing the OneOrMore(label + "." + FollowedBy(...)) construction).scheme_less_url and scheme_less_url_complete grammars no longer also match URLs with a scheme; they only match URLs without one (#244). parse_urls and parse_urls_complete now run the scheme-ful grammar first and mask each matched URL before running the scheme-less grammar, so user-facing output of find_iocs is unchanged but embedded scheme-less hosts inside a scheme-ful URL's query (e.g. https://shortener.com/?url=foo.com/bar) no longer surface as a second URL.urls_complete now accepts @ in URL paths, matching the RFC 3986 pchar definition (e.g. https://example.com/users/@alice is now captured in full).parse_user_agents no longer absorbs a trailing token like TLP from input such as Mozilla/4.0 (...) TLP:RED. A bare (version-less) platform token must not be immediately followed by :. Versioned platforms (e.g. Chrome/91.0) are unaffected. (#227)socket_addresses IOC type with a matching parse_socket_addresses helper (#248). Accepts ipv4:port and bracketed [ipv6]:port shapes with a 1..65535 port range. IPv6 host validation reuses the existing _is_valid_ipv6 helper so the same shortened forms accepted by parse_ipv6_addresses are accepted here too. Observed text is preserved verbatim (no leading-zero normalization). Port 0 is intentionally excluded as IANA-reserved.ipv6_cidrs IOC type with a matching parse_ipv6_cidrs helper (#121). It accepts the same shortened/::/trailing-:: forms as the existing IPv6 address parser plus a /0..128 bit range, and integrates with the existing CIDR-vs-URL and parse_address_from_cidr handling. CIDR parsing runs against the pre-fang text so the standard fanger (which rewrites ::/ to ://) cannot silently swallow indicators like 2001:db8::/32.logging module (#287). The package follows the standard library convention of attaching a NullHandler so consumers see no output unless they configure logging. find_iocs emits INFO at start/finish (text length, IOC type count), WARNING when unsupported types are passed via included_ioc_types (they are now ignored rather than silently treated as misses), and DEBUG for per-type result counts and lower-level transforms (text fanging, URL cleaning). Apps can opt in with e.g. logging.getLogger("ioc_finder").setLevel(logging.DEBUG).Performance improvements on non-default ioc types
Performance improvements on non-default ioc types
uv ecosystem so pyproject.toml and uv.lock are updated atomically.requirements.txt / requirements_dev.txt compatibility exports and the make export-requirements target. Contributors should use uv sync --locked --group dev to set up a dev environment.Dedup imphashes and authentihashes
Dedup imphashes and authentihashes
parse_imphashes_ and parse_authentihashes_ no longer return the same hash multiple times when the input labels it with different separators (e.g. imphash: <h>, imphash <h>, imphash - <h>). The deduplication now runs on the extracted hash itself rather than the full keyword+separator+hash match string. (#213)Performance improvements for default indicators
Performance improvements for default indicators
:: (the unspecified address) and trailing-:: forms (e.g. 1::), which were previously rejected by the grammar.Focussing on major performance gains
Focussing on major performance gains
parse_complete_email_addresses, parse_email_addresses, parse_ipv6_addresses, parse_imphashes_, parse_authentihashes_, parse_urls, parse_urls_complete, parse_mac_addresses, parse_user_agents, and parse_file_paths now use cheap candidate regexes to narrow where the pyparsing grammar runs, dropping benchmark mean from ~7.1s to ~2.4s on the long benchmark article. The parse_domain_names and ATT&CK helpers were folded onto the same shared _scan_candidates helper (no behavior change).scripts/find_hotspots.py to reproduce per-grammar timings and a cProfile drill-down for future tuning.DEFAULT_IOC_TYPES has been reduced from 30 entries to 9 common indicator types (domains, urls, ipv4s, ipv6s, email_addresses, md5s, sha1s, sha256s, cves) to speed up parsing in the typical case. Callers that relied on default-parsing of obscure types (e.g. bitcoin_addresses, attack_techniques, imphashes, urls_complete, etc.) must now pass included_ioc_types=SUPPORTED_IOC_TYPES (or an explicit subset) to get them. The CLI parses the common defaults by default; pass --all to parse every supported type. (#340)SUPPORTED_IOC_TYPES constant exposing the full list of parseable IOC types. Both DEFAULT_IOC_TYPES and SUPPORTED_IOC_TYPES are now exported from the ioc_finder package. (#340)--all CLI flag to parse every supported indicator type instead of the common defaults. (#340)parse_imphashes and parse_authentihashes keyword arguments from find_iocs(), along with the --no_import_hashes and --no_authentihashes CLI flags. To disable parsing of these hash types, omit "imphashes" / "authentihashes" from included_ioc_types instead. (#333)Performance improvements
Performance improvements
…/ --no_authentihashes CLI flags, are now deprecated in favor of omitting "imphashes" / "authentihashes" from included_ioc_types. Passing these argumen…
parse_imphashes and parse_authentihashes keyword arguments to find_iocs(), and the corresponding --no_import_hashes / --no_authentihashes CLI flags, are now deprecated in favor of omitting "imphashes" / "authentihashes" from included_ioc_types. Passing these arguments emits a DeprecationWarning (CLI flags print a notice to stderr). They will be removed in a future release. (#225)1/3, and MD5/SHA1/SHA256 hashes starting with bc1) (#226)Migrated from pip/setuptools to uv for dependency management and packaging
python:3.10.2-buster to python:3.14-slim-bookwormsetup.py, setup.cfg, and mypy.ini (configuration consolidated into pyproject.toml)To speed URL parsing, we no longer parse URLs with userinfo "@" in the authority (see URL syntax guide for more details)
userinfo "@" in the authority (see URL syntax guide for more details)
URL boundary to better respect the conventions of human language regarding quotation marks and parentheses
Update required version of ioc-fanger which fixes issues with non-http(s) URL schemes
Poorly designed grammars which were SIGNIFICANTLY slowing down this project
Removed duplicative function calls
*Possible breaking change:* Update required pyparsing version to v3
ua-... and UA-... will be matched, but uA-... will not) (this makes the parsing consistent with how Google Adsense Publisher IDs are parsed)included_ioc_types option to only parse specified IOC types
### Added - Support for Python 3.10 (#188) ### Removed - Phone number parsing (#155) - Support for Python 3.6
ASN grammar improved to reduce false positives by not matching on lower-case "as "
"as " (#136)Made all boolean arguments keyword-only arguments
_prepare_text function public (prepare_text) (#114)no_urls_without_schemes to parse_urls_without_scheme (#109)Pinned specific ioc-fanger version (this prevents an error where ioc-fanger was removing a URL in the query parameter of another URL - see #104)
Updating library such that CIDR ranges are not detected as URLs when parse_urls_without_scheme=True (see #91)
Improved word boundary (specifically of MAC address and IP address grammars)
Concurrency (through the use of concurrent.futures)
Nothing published for this version
Added parsing Monero addresses (see #94)
_remove_url_paths (a function used behind the scenes by the ioc finder - see #70)You can now ingest text using the cli. For example, this now works: cat foo.text | ioc-finder.
cat foo.text | ioc-finder.We are now parsing observables from URL paths by default (see https://github.com/fhightower/ioc-finder/issues/87). If you would like to disable this f
parse_from_url_path keyword argument to False when calling the find_iocs function (e.g. parse_from_url_path=False).The change log was added for version 3.1.2
The change log was added for version 3.1.2
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →