<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Grujowmi</title>
    <description>The latest articles on DEV Community by Grujowmi (@grujowmi).</description>
    <link>https://dev.to/grujowmi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3852025%2Fe533a9bc-4da2-4bba-ac9a-710bf3ba1fdc.jpeg</url>
      <title>DEV Community: Grujowmi</title>
      <link>https://dev.to/grujowmi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grujowmi"/>
    <language>en</language>
    <item>
      <title>SecureWipe: ANSSI and NIST-compliant secure disk erasure, because rm -rf isn't enough</title>
      <dc:creator>Grujowmi</dc:creator>
      <pubDate>Mon, 30 Mar 2026 17:32:36 +0000</pubDate>
      <link>https://dev.to/grujowmi/securewipe-anssi-and-nist-compliant-secure-disk-erasure-because-rm-rf-isnt-enough-i5b</link>
      <guid>https://dev.to/grujowmi/securewipe-anssi-and-nist-compliant-secure-disk-erasure-because-rm-rf-isnt-enough-i5b</guid>
      <description>&lt;p&gt;In a medical environment subject to HDS (French healthcare data hosting regulations) and NIS2, decommissioning a hard drive is not a trivial operation. A &lt;code&gt;rm -rf&lt;/code&gt; or even a quick format doesn't destroy data — it just dereferences the files. The data remains physically present and recoverable. I built &lt;strong&gt;SecureWipe&lt;/strong&gt; to have an auditable erasure tool, compliant with recognized standards, and usable without friction in a real operational context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just use &lt;code&gt;shred&lt;/code&gt;, &lt;code&gt;wipe&lt;/code&gt;, or DBAN?
&lt;/h2&gt;

&lt;p&gt;These tools exist and work. But they come with real problems in a professional context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No native traceability&lt;/strong&gt;: no usable erasure report for an audit or a documented decommissioning procedure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vague compliance&lt;/strong&gt;: &lt;code&gt;shred&lt;/code&gt; does random passes, but doesn't align with any specific standard (ANSSI, NIST)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DBAN has been end-of-life since 2015&lt;/strong&gt;, replaced by Blancco which is commercial&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No integration into existing Python workflows&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SecureWipe addresses these gaps: written in Python, it documents every operation and implements referenced erasure methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implemented standards
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ANSSI Tier 1 and Tier 2
&lt;/h3&gt;

&lt;p&gt;The French national cybersecurity agency (ANSSI) defines two levels in its data destruction guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tier 1&lt;/strong&gt;: logical erasure by overwrite (1 pass of zeros or random data). Sufficient for most internal decommissioning cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tier 2&lt;/strong&gt;: enhanced erasure with multiple passes and verification. Required for media that held sensitive or classified data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  NIST SP 800-88 Rev.2
&lt;/h3&gt;

&lt;p&gt;The U.S. reference standard for media sanitization. It defines three levels: &lt;em&gt;Clear&lt;/em&gt;, &lt;em&gt;Purge&lt;/em&gt;, and &lt;em&gt;Destroy&lt;/em&gt;. SecureWipe covers the &lt;em&gt;Clear&lt;/em&gt; and &lt;em&gt;Purge&lt;/em&gt; levels depending on the media type and data sensitivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SecureWipe does
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SecureWipe v1.1.0
├── Automatic detection of available disks
├── Erasure level selection (ANSSI T1 / ANSSI T2 / NIST Clear / NIST Purge)
├── Overwrite passes execution with verification
├── Generation of a timestamped erasure report
└── Operation logging (disk, method, duration, result)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated report can be used directly in a decommissioning file or handed to a destruction vendor to complete the audit trail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ANSSI Tier 2 erasure on /dev/sdb&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;python3 securewipe.py &lt;span class="nt"&gt;--device&lt;/span&gt; /dev/sdb &lt;span class="nt"&gt;--method&lt;/span&gt; anssi-t2

&lt;span class="c"&gt;# NIST Purge erasure with report generation&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;python3 securewipe.py &lt;span class="nt"&gt;--device&lt;/span&gt; /dev/sdb &lt;span class="nt"&gt;--method&lt;/span&gt; nist-purge &lt;span class="nt"&gt;--report&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script refuses to run without elevated privileges and requires explicit confirmation with the device name before doing anything — no accidental wipes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Python?
&lt;/h2&gt;

&lt;p&gt;Python ships natively on all common Linux distributions and maintenance live USB environments. No dependency to compile, no binary to distribute, code that's directly readable and auditable.&lt;/p&gt;

&lt;p&gt;For a security tool designed to run in critical contexts (end-of-life medical server, hardware returned to a vendor), code transparency is a non-negotiable requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creation context: HDS and NIS2
&lt;/h2&gt;

&lt;p&gt;In a healthcare facility, decommissioning a storage medium that held health data (EHR, PACS, RIS data) is a regulated operation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HDS&lt;/strong&gt; mandates traceability of the destruction of hosted data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NIS2 Article 21&lt;/strong&gt; covers asset lifecycle management, including secure decommissioning&lt;/li&gt;
&lt;li&gt;Internal &lt;strong&gt;ISMS/PSSI procedures&lt;/strong&gt; must document the erasure method used&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SecureWipe generates exactly what you need to fill that box: a timestamped report, with the applied method, on which device, on which date, with what result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Known limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSDs and NVMe&lt;/strong&gt;: overwrite-based erasure is less reliable on flash media due to wear leveling and spare cells. On these drives, the recommended approach is &lt;code&gt;NVMe Secure Erase&lt;/code&gt; (via &lt;code&gt;nvme format&lt;/code&gt;) or physical destruction. SecureWipe flags this explicitly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encrypted drives&lt;/strong&gt;: if the drive is encrypted (LUKS, BitLocker), destroying the encryption key plus one overwrite pass is generally sufficient. SecureWipe can be used as a complement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  License and contributions
&lt;/h2&gt;

&lt;p&gt;Project released under the &lt;strong&gt;GPL V3&lt;/strong&gt;, code available on GitHub.&lt;/p&gt;

&lt;p&gt;Contributions welcome: native NVMe Secure Erase support, TUI interface, integration into Ansible decommissioning playbooks.&lt;/p&gt;

&lt;p&gt;→ &lt;strong&gt;&lt;a href="https://github.com/Grujowmi/SecureWipe" rel="noopener noreferrer"&gt;github.com/Grujowmi/SecureWipe&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built from a real operational need, in a medical environment under HDS and NIS2 compliance or others. If you manage end-of-life assets in a regulated sector, feedback in the comments is very welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>python</category>
      <category>opensource</category>
      <category>news</category>
    </item>
    <item>
      <title>ShadowFortress: how I aggregate hundreds of IP blocklists into a single ready-to-use file</title>
      <dc:creator>Grujowmi</dc:creator>
      <pubDate>Mon, 30 Mar 2026 17:29:02 +0000</pubDate>
      <link>https://dev.to/grujowmi/shadowfortress-how-i-aggregate-hundreds-of-ip-blocklists-into-a-single-ready-to-use-file-4dem</link>
      <guid>https://dev.to/grujowmi/shadowfortress-how-i-aggregate-hundreds-of-ip-blocklists-into-a-single-ready-to-use-file-4dem</guid>
      <description>&lt;p&gt;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 &lt;strong&gt;ShadowFortress&lt;/strong&gt; to solve this once and for all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual problem
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What ShadowFortress does
&lt;/h2&gt;

&lt;p&gt;ShadowFortress is an &lt;strong&gt;open source IP blocklist aggregator&lt;/strong&gt; that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Collects&lt;/strong&gt; multiple public blocklist sources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deduplicates&lt;/strong&gt; all IP addresses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selects&lt;/strong&gt; the most redundant IPs (those appearing across the highest number of sources)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Applies a private whitelist&lt;/strong&gt; to avoid false positives on legitimate IP ranges&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generates two separate files&lt;/strong&gt;: one for inbound filtering, one for outbound&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-updates every 6 hours&lt;/strong&gt; via GitHub Actions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The cap is set at &lt;strong&gt;100,000 IP addresses maximum&lt;/strong&gt;, which is roughly what most network appliances can absorb without performance degradation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generated files
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;blacklist_inbound.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block incoming connections from malicious IPs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;blacklist_outbound.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block outgoing connections to compromised destinations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;STATS.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Statistics: volumes, trends, active sources&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Files are available directly via raw GitHub URLs, making them easy to consume from any script or network solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration examples
&lt;/h2&gt;

&lt;p&gt;No installation required. You consume the files directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  FortiGate (my primary use case)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From FortiGate CLI&lt;/span&gt;
config firewall address
    edit &lt;span class="s2"&gt;"ShadowFortress-Inbound"&lt;/span&gt;
        &lt;span class="nb"&gt;set type &lt;/span&gt;iprange
        &lt;span class="nb"&gt;set &lt;/span&gt;comment &lt;span class="s2"&gt;"ShadowFortress blocklist - inbound"&lt;/span&gt;
    next
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  iptables / ipset
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fetch the list and load it into ipset&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://raw.githubusercontent.com/Grujowmi/ShadowFortress/main/blacklist_inbound.txt | &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;ip&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;ipset add blocklist_inbound &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ip&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  nftables
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cisco (ACL)
&lt;/h3&gt;

&lt;p&gt;The list can be parsed to generate ACLs via a Python script, or integrated into a configuration management solution like Ansible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why redundancy-based selection?
&lt;/h2&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The result: a &lt;strong&gt;shorter, more accurate list with fewer false positives&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The private whitelist
&lt;/h2&gt;

&lt;p&gt;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.).&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  License and contributions
&lt;/h2&gt;

&lt;p&gt;The project is licensed under &lt;strong&gt;GNU GPL v3&lt;/strong&gt; (the AGPL-3.0 badge on the repo is worth correcting — the actual license in the &lt;code&gt;LICENSE&lt;/code&gt; file is GPLv3).&lt;/p&gt;

&lt;p&gt;Contributions are welcome: new sources to aggregate, fixes, improvements to the deduplication pipeline.&lt;/p&gt;

&lt;p&gt;→ &lt;strong&gt;&lt;a href="https://github.com/Grujowmi/ShadowFortress" rel="noopener noreferrer"&gt;github.com/Grujowmi/ShadowFortress&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;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.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>blocklist</category>
      <category>opensource</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
