DEV Community

Cover image for ShadowFortress: how I aggregate hundreds of IP blocklists into a single ready-to-use file
Grujowmi
Grujowmi

Posted on

ShadowFortress: how I aggregate hundreds of IP blocklists into a single ready-to-use file

For a while I've been looking for a clean way to feed my FortiGate with IP threat intel without having to manually maintain an unmanageable list. Public blocklists are plentiful, inconsistent in quality, and heavily redundant. So I built ShadowFortress to solve this once and for all.

The actual problem

As a CISO, I need to block inbound and outbound traffic to and from known malicious IPs: C2 servers, scanners, spam relays, offensively used Tor exit nodes, etc.

The market offers paid solutions (FortiGuard Threat Intelligence feeds, CrowdSec, etc.), but nothing that's truly simple to consume as a raw IP file, free, and automatically maintained.

Public sources exist (blocklist.de, feodotracker, spamhaus, etc.) but aggregating them properly takes real work: deduplication, frequency-based selection, false positive exclusion.

What ShadowFortress does

ShadowFortress is an open source IP blocklist aggregator that:

  1. Collects multiple public blocklist sources
  2. Deduplicates all IP addresses
  3. Selects the most redundant IPs (those appearing across the highest number of sources)
  4. Applies a private whitelist to avoid false positives on legitimate IP ranges
  5. Generates two separate files: one for inbound filtering, one for outbound
  6. Auto-updates every 6 hours via GitHub Actions

The cap is set at 100,000 IP addresses maximum, which is roughly what most network appliances can absorb without performance degradation.

Generated files

File Purpose
blacklist_inbound.txt Block incoming connections from malicious IPs
blacklist_outbound.txt Block outgoing connections to compromised destinations
STATS.md Statistics: volumes, trends, active sources

Files are available directly via raw GitHub URLs, making them easy to consume from any script or network solution.

Integration examples

No installation required. You consume the files directly.

FortiGate (my primary use case)

# From FortiGate CLI
config firewall address
    edit "ShadowFortress-Inbound"
        set type iprange
        set comment "ShadowFortress blocklist - inbound"
    next
end
Enter fullscreen mode Exit fullscreen mode

For a clean integration using External Block List (EBL), point directly to the raw URL of the file — FortiOS will refresh it periodically on its own.

iptables / ipset

# Fetch the list and load it into ipset
curl -s https://raw.githubusercontent.com/Grujowmi/ShadowFortress/main/blacklist_inbound.txt | \
  while read ip; do ipset add blocklist_inbound "$ip" 2>/dev/null; done
Enter fullscreen mode Exit fullscreen mode

nftables

table inet filter {
    set blocklist_inbound {
        type ipv4_addr
        flags interval
        # populate via script from blacklist_inbound.txt
    }

    chain input {
        type filter hook input priority 0;
        ip saddr @blocklist_inbound drop
    }
}
Enter fullscreen mode Exit fullscreen mode

Cisco (ACL)

The list can be parsed to generate ACLs via a Python script, or integrated into a configuration management solution like Ansible.

Why redundancy-based selection?

This is the core of the project. Rather than taking the union of all sources (which can produce millions of IPs with a lot of noise), ShadowFortress selects IPs that appear across the highest number of distinct sources.

The reasoning: an IP listed in 10 different sources is far more likely to be genuinely malicious than one listed in a single source that might be stale or poorly maintained.

The result: a shorter, more accurate list with fewer false positives.

The private whitelist

A whitelist mechanism is applied before the files are generated. It excludes IP ranges that would trigger false positives in my environment (CDNs, legitimate cloud services, business partners, etc.).

This whitelist is not public — each user should manage their own exclusions based on their context. If you want to implement the same logic, the principle is straightforward: before publishing the files, filter out any IPs that match your allowlist.

License and contributions

The project is licensed under GNU GPL v3 (the AGPL-3.0 badge on the repo is worth correcting — the actual license in the LICENSE file is GPLv3).

Contributions are welcome: new sources to aggregate, fixes, improvements to the deduplication pipeline.

github.com/Grujowmi/ShadowFortress


This project was born from a real operational need in a medical environment subject to NIS2 and HDS compliance requirements. If you have experience integrating this with other appliances, feel free to open an issue or drop a comment below.

Top comments (0)