Open-source project
Bert-JanP/Open-Source-Threat-Intel-Feeds avatar
Bert-JanP/Open-Source-Threat-Intel-Feeds

Open-Source-Threat-Intel-Feeds: a catalogue of free IOC feeds and how to hunt with them

This repository contains Open Source freely usable Threat Intel feeds that can be used without additional requirements. Contains multiple types such as IP, URL, CVE and Hash.

964 stars104 forksPythonBSD-3-Clause

At a glance

What is it?
Bert-JanP/Open-Source-Threat-Intel-Feeds is a curated index of freely usable IP, URL, hash and CVE feeds that need no account or API token, plus KQL patterns for pulling them into Defender and Sentinel. It points at sources rather than hosting them, and it publishes no releases, so the value sits in discovery and vetting, not in delivery.
Who is it for?
Adopt this repository if you hunt on Defender for Endpoint or Sentinel and want a vetted list of sources that work without credentials. Do not treat it as a feed pipeline: it stores links, not data, and it ships no releases, so the last push on 2026-10-20 is your only version marker.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A CSV index of feeds that require no account

The product here is a single structured file. ThreatIntelFeeds.csv is organised by Vendor, Description, Category and URL, and the surrounding README turns it into a directory of where free threat intelligence lives. The categories span SSL, IP, DNS, URL, MD5, SHA1, SHA256, CVEID, JA3 and NamePipes, and the published count table gives each one a size: 78 IP feeds, 23 URL feeds, 17 DNS feeds, 12 MD5 feeds, 8 SHA256 feeds, 5 SHA1 feeds, 4 CVEID feeds, and single entries for SSL, RANSOMWARELEAK, JA3 and NamePipe.

That catalogue answers a narrow question: where can a defender pull indicators without creating an account, signing a contract or handling an API token? The answer is a list of vendor sections. Abuse.ch contributes SSL blacklists, host files, Feodo Tracker, ThreatFox, Bazaar and URLhaus exports. Blocklist.de contributes SSH, mail, Apache, IMAP, bot and brute force lists across nine endpoints. IPSum contributes eight text files, one per aggression level. C2IntelFeeds contributes CSV files of command and control addresses and domains.

For a threat hunter, the alternative is not zero work but unpaid work: reading vendor documentation to find each export URL and then checking whether its license permits your use. This index front-loads that search and applies one explicit filter to it, since the contribution rules require that a source be free and usable without any account or API token needed.

Eleven feed categories with incompatible file shapes

The categories are not interchangeable, and the repository makes no attempt to normalise them. An IP feed is a flat list of addresses, sometimes plain text as in the blocklist.de entries and sometimes CSV as in the C2IntelFeeds files. A URL feed carries full addresses. Hash feeds are split across MD5, SHA1 and SHA256 because the upstream vendors publish separate exports per algorithm, with Bazaar serving recent MD5, SHA1 and SHA256 lists and ThreatFox serving recent MD5 and SHA256 exports.

Other categories do not even hold indicators in the usual sense. JA3 is a TLS fingerprint format, and the SSL category points at SSL blacklists tied to the Abuse.ch SSLBL service. NamePipes is a list of Windows pipe names. CVEID refers to vulnerability identifiers rather than observed attacker infrastructure. The DNS category mixes resolvers and hosts files.

This shape mismatch is the practical constraint on use. Any consumer has to know per feed what the first line looks like, whether the file has a header, and whether one row equals one indicator. The README shows this in its simplest form by ignoring the first record when parsing a CSV, which is the right move for a file with a header row and the wrong move for a file without one. Nothing in the index tells you which case applies to which vendor, so that knowledge stays with the person wiring the feed.

Loading a C2 IP feed into KQL with externaldata

The README demonstrates the consumption path with the Kusto externaldata operator, which reads a remote file and turns it into a table you can join or filter against. The first example pulls the 30 day command and control IP list:

code
let C2IntelFeeds = externaldata(IP: string, ioc:string)[@"https://raw.githubusercontent.com/drb-ra/C2IntelFeeds/master/feeds/IPC2s-30day.csv"] with (format="csv", ignoreFirstRecord=True);
C2IntelFeeds
| take 100

The operator takes a schema of column names and types, a URL and a set of format options. Here the schema is IP and ioc, the format is csv and ignoreFirstRecord is set, which drops the header row so that the hundred rows returned by take 100 are indicators rather than a column label. The result is a normal table, so it can be named, joined, and reused.

Note what this does not do. The fetch happens inside the query, at query time, against a third party host that this repository does not control. Nothing pins the content, so the same query can return different rows tomorrow, and a feed that changes format upstream becomes a parsing error rather than an empty result. There is also no authentication step, which matches the requirement the project places on its sources, and no retry or caching behaviour described anywhere in the documentation.

Joining Defender network events against the C2 IP list

The second documented pattern is the one most people would build anyway, so it is worth reading line by line:

code
let C2IntelFeeds = externaldata(IP: string, ioc:string)[@"https://raw.githubusercontent.com/drb-ra/C2IntelFeeds/master/feeds/IPC2s-30day.csv"] with (format="csv", ignoreFirstRecord=True);
let IPList = C2IntelFeeds
| project IP;
DeviceNetworkEvents
| where RemoteIP in (IPList)
| join kind=inner C2IntelFeeds on $left.RemoteIP == $right.IP
| extend GeoIPInfo = geo_info_from_ip_address(RemoteIP)
| extend country = tostring(parse_json(GeoIPInfo).country), state = tostring(parse_json(GeoIPInfo).state), city = tostring(parse_json(GeoIPInfo).city), latitude = tostring(parse_json(GeoIPInfo).latitude), longitude = tostring(parse_json(GeoIPInfo).longitude)
| project Timestamp, DeviceName, RemoteIP, RemotePort, RemoteUrl, ioc

The flow is filter, then join, then enrich, then narrow. DeviceNetworkEvents is filtered to rows whose RemoteIP appears in the extracted IP column, an inner join pulls the matching feed rows back in, geo_info_from_ip_address adds location fields, and the final projection keeps the endpoint name, the remote port, the remote URL and the indicator itself.

The interesting part is the redundancy. The where clause and the join both filter on the same key, so the join is doing enrichment work rather than narrowing the result set. The final project keeps the ioc column, which is what tells an analyst why a row was returned, and it keeps the endpoint identifier, which is what turns a hit into a ticket. The pattern is written for Defender for Endpoint network events and Sentinel tables, and the README points to a separate repository of KQL hunting queries for those products.

Validating a new row before the statistics table changes

The contribution flow is the part of this repository that contains actual code, and it lives in the Scripts directory. The top level of the project holds .github/, Img/, LICENSE, README.md, Scripts/ and ThreatIntelFeeds.csv, with the validator and the table generator inside Scripts/.

A pull request has to do five things. Add the link to the feed in README.md, creating a new section if the source fits none of the existing ones. Add the details to ThreatIntelFeeds.csv using the column order the repository expects:

code
    Vendor;Description;Category;Url

The Category value has to match one of the feed categories listed in the README. The source must be free and usable without any account or API token. Then the CSV content has to be validated with Validator.py, which the README says can be run from the script directory, and the statistics table has to be regenerated with GenerateTableStatistics.py, which writes the markdown table to StatisticsTable.md so it can be pasted into the README.

Two consequences follow from that design. The counts in the README are generated rather than hand maintained, so a contributor who adds a feed but forgets the generator leaves the table stale and the gate may not catch it. And the repository treats a row in the CSV as a fact to be validated, which is a higher bar than a link dump, even though the validator cannot check whether a source is actually free.

The index does not refresh the feeds it lists

The largest limitation is structural and worth stating plainly: this repository holds URLs, not indicators. Nothing here downloads the 78 IP feeds on a schedule, normalises them, expires entries or pushes them to your platform. The count table is a statement about how many links exist in the CSV, not about how much fresh intelligence is available at any moment.

Licensing is the second limitation, and it is explicitly disclaimed rather than solved. The README states that the content is served as is, that conditions have to be researched before use in a business environment, and that some content may not be freely usable under certain conditions. Individual sections carry their own terms of service links, for the SSLBL blacklist service, the Feodo Tracker blocklist and Blocklist.de. The repository itself is BSD-3-Clause, but that licence covers the index and the Python scripts, not the third party feeds it points at, and a team that pushes these lists into a commercial product needs to check each upstream policy separately.

Maintenance follows from the same shape. The repository is not archived, and the last push was on 2026-10-20, so work is still landing. It has no GitHub releases, however, so there is no tag to pin, no changelog to read and no upgrade step beyond pulling the main branch and running the two scripts again.

Curated catalogue versus running your own ingest job

The realistic alternative is to skip this repository entirely and pull from the upstream vendors yourself. The endpoints it lists, such as the Feodo Tracker IP blocklist, the URLhaus recent CSV export and the SSLBL JA3 fingerprint file, are reachable on their own, and an engineering team with an existing scheduler and a normalised schema can wire them in directly.

The difference in approach is that the upstream path gives you control over refresh cadence, format normalisation and expiry, and it removes a dependency on someone else's link list staying correct. The catalogue path gives you something else: a vetting rule that something other people applied, a category taxonomy so that a feed for JA3 fingerprints is distinguishable from a feed for pipe names, and a discovery list that turns a search across many vendor sites into a single file to read.

That saving is real but bounded. The vetting rule is only as strong as the contributor who applied it, and the README's own contribution process asks a human to verify one thing, free and no account, rather than anything about data quality. Teams that already run a scheduled collector gain little; teams starting from zero gain a shortlist worth an afternoon of reading. For Microsoft shops hunting on Defender or Sentinel, the documented KQL removes most of the remaining work, since the hard part of a first hunt is writing the join correctly, and that part is written down.

Editorial conclusion

Adopt this repository if you hunt on Defender for Endpoint or Sentinel and want a vetted list of sources that work without credentials. Do not treat it as a feed pipeline: it stores links, not data, and it ships no releases, so the last push on 2026-10-20 is your only version marker. Before relying on it, check the terms of service listed for each vendor and confirm that the Python validation scripts in Scripts/ still run against your copy of ThreatIntelFeeds.csv.

Frequently asked questions

Do the feeds listed in Open-Source-Threat-Intel-Feeds need an account or an API token?

No. The contribution rules require that a listed source be free and usable without any account or API token, and the feeds shown in the KQL examples are fetched from public raw URLs with no credentials.

How do I pull one of these IOC feeds into Microsoft Defender for Endpoint or Sentinel?

Use the Kusto externaldata operator to read the remote file into a table, then join it against a telemetry table such as DeviceNetworkEvents. The README shows both a minimal load and a fuller join that adds geolocation fields.

How do I contribute a new feed to Open-Source-Threat-Intel-Feeds?

Open a pull request that adds the link to README.md, adds a row to ThreatIntelFeeds.csv in Vendor;Description;Category;Url order, validates the CSV with Validator.py in the Scripts directory, and regenerates the statistics table with GenerateTableStatistics.py into StatisticsTable.md.

What licence applies to Open-Source-Threat-Intel-Feeds and to the feeds it lists?

The repository is BSD-3-Clause. The README states the content is served as is and that conditions for business use must be researched per source, with terms of service links given for the SSLBL blacklist, the Feodo Tracker blocklist and Blocklist.de.

Official sources

  1. Bert-JanP/Open-Source-Threat-Intel-Feeds on GitHub
  2. Issues
  3. License: BSD-3-Clause
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bert-janp-open-source-threat-intel-feeds.svg)](https://hysenlabs.com/projects/bert-janp-open-source-threat-intel-feeds)

Was this useful?