<?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: Freemen HOUNGBEDJI</title>
    <description>The latest articles on Forem by Freemen HOUNGBEDJI (@freemen_tech).</description>
    <link>https://forem.com/freemen_tech</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%2F3754857%2F0c8c529a-2768-4ce7-a55c-bcf97afa1345.jpg</url>
      <title>Forem: Freemen HOUNGBEDJI</title>
      <link>https://forem.com/freemen_tech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/freemen_tech"/>
    <language>en</language>
    <item>
      <title>I Built a URL Threat Analyzer That Detects Phishing in Real-Time — Here's How It Works published</title>
      <dc:creator>Freemen HOUNGBEDJI</dc:creator>
      <pubDate>Sat, 09 May 2026 12:29:40 +0000</pubDate>
      <link>https://forem.com/freemen_tech/i-built-a-url-threat-analyzer-that-detects-phishing-in-real-time-heres-how-it-works-published-bhm</link>
      <guid>https://forem.com/freemen_tech/i-built-a-url-threat-analyzer-that-detects-phishing-in-real-time-heres-how-it-works-published-bhm</guid>
      <description>&lt;p&gt;&lt;em&gt;Every day, millions of people click malicious URLs without knowing it. Phishing pages look legitimate. Shortened links hide their destination. Freshly registered domains slip past blockers.&lt;br&gt;
I got tired of copy-pasting URLs into clunky online scanners and waiting 10 seconds for a result — so I built SnifURL.&lt;/em&gt;&lt;br&gt;
&lt;a href="//snifurl.online"&gt;Live&lt;/a&gt;&lt;br&gt;
&lt;a href="//github.com/FreemenTech/Snifurl"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is SnifURL?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SnifURL is a real-time URL threat analyzer. You paste a URL, it runs it through 13 heuristic checks in parallel, and returns a risk score from 0 to 100 with a full breakdown of every signal it found.&lt;br&gt;
No black box. No "we flagged it, trust us." Every point added or subtracted is explained.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{&lt;br&gt;
  "url": "https://paypa1-secure-login.tk/verify",&lt;br&gt;
  "score": 91,&lt;br&gt;
  "risk_level": "CRITICAL",&lt;br&gt;
  "recommendation": "Phishing almost certain — block immediately",&lt;br&gt;
  "details": [&lt;br&gt;
    "Suspicious TLD (.tk — Freenom free domain) (+18)",&lt;br&gt;
    "Brand impersonation detected: 'paypa1' looks like 'paypal' (+25)",&lt;br&gt;
    "Domain registered 3 days ago (+20)",&lt;br&gt;
    "Homograph character detected: '1' replacing 'l' (+15)",&lt;br&gt;
    "No valid SSL certificate (+13)"&lt;br&gt;
  ]&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Risk Score System&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🟢 0–14 — &lt;strong&gt;SAFE&lt;/strong&gt; No significant indicators. The URL looks clean.&lt;br&gt;
🟡 15–34 — &lt;strong&gt;LOW&lt;/strong&gt; Probably safe, but worth a second look before clicking.&lt;br&gt;
🟠 35–54 — &lt;strong&gt;MEDIUM&lt;/strong&gt; Suspicious. Inspect manually before trusting it.&lt;br&gt;
🔴 55–74 — &lt;strong&gt;HIGH&lt;/strong&gt; Very suspicious — block it unless you're 100% sure of the source.&lt;br&gt;
🚨 75–100 — &lt;strong&gt;CRITICAL&lt;/strong&gt; Phishing almost certain. Block immediately.&lt;br&gt;
The score is additive: each indicator adds or subtracts points based on its confidence weight. This makes results explainable and debuggable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 13 Heuristic Indicators&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's exactly what SnifURL checks — and why each one matters.&lt;br&gt;
&lt;strong&gt;1. TLD Reputation&lt;/strong&gt;&lt;br&gt;
Free TLDs like .tk, .ml, .cf, .ga, .gq (Freenom) are massively over-represented in phishing campaigns. Crypto TLDs like .xyz, .top also rank high. High-risk ccTLDs are weighted accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Direct IP in URL&lt;/strong&gt;&lt;br&gt;
&lt;a href="http://192.168.1.1/login" rel="noopener noreferrer"&gt;http://192.168.1.1/login&lt;/a&gt; — no legitimate service asks you to log in via a raw IP address. This is a strong phishing signal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Brand Impersonation&lt;/strong&gt;&lt;br&gt;
The engine scans the subdomain and path against a dictionary of major brands (paypal, google, apple, amazon, microsoft, netflix...) and checks for typosquatting variations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Homograph Attacks&lt;/strong&gt;&lt;br&gt;
Unicode lookalike characters are a sneaky attack vector. pаypal.com with a Cyrillic а looks identical to paypal.com. SnifURL detects non-ASCII characters and flags them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. SSL Certificate Validity&lt;/strong&gt;&lt;br&gt;
Checks if the certificate is valid and evaluates issuer trust. A self-signed cert on a "bank login" page? Red flag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. WHOIS Domain Age&lt;/strong&gt;&lt;br&gt;
New domains are suspicious. A domain registered 2 days ago asking for your password is a massive red flag. SnifURL queries WHOIS and penalizes recently created domains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. DNS Resolution&lt;/strong&gt;&lt;br&gt;
If the domain doesn't even resolve — it's either dead or a trap. Simple check, non-zero value.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;URL Shorteners
bit.ly, tinyurl.com, t.co — shorteners hide the real destination. SnifURL flags them and encourages redirect inspection.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;9. Double File Extensions&lt;/strong&gt;&lt;br&gt;
invoice.pdf.exe is a classic malware trick. The engine scans the URL path for chained extensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. @ Character in URL&lt;/strong&gt;&lt;br&gt;
&lt;a href="http://legitimate.com@evil.com/phish" rel="noopener noreferrer"&gt;http://legitimate.com@evil.com/phish&lt;/a&gt; — browsers follow the part after @. This old trick still catches people off guard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. Non-Standard Ports&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://mybank.com:8080/login" rel="noopener noreferrer"&gt;https://mybank.com:8080/login&lt;/a&gt; is a sign something is off. Legit services run on 443.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. Excessive URL Encoding&lt;/strong&gt;&lt;br&gt;
%68%74%74%70%73%3A%2F%2F... — heavy encoding often signals an attempt to obfuscate a malicious destination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;13. Subdomain Depth &amp;amp; Hyphens&lt;/strong&gt;&lt;br&gt;
secure-login-verify.paypal.accounts.malicious.com — deep subdomains and excessive hyphens are classic phishing patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How the Parallel Analysis Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Network checks (DNS, WHOIS, SSL) are the slow part. Running them sequentially would add 3–5 seconds of latency. Instead, SnifURL runs them concurrently with Python's ThreadPoolExecutor:&lt;br&gt;
python# analyseur_url.py (simplified)&lt;br&gt;
from concurrent.futures import ThreadPoolExecutor, as_completed&lt;/p&gt;

&lt;p&gt;def analyze(url: str) -&amp;gt; dict:&lt;br&gt;
    results = {}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;with ThreadPoolExecutor(max_workers=4) as executor:
    futures = {
        executor.submit(check_ssl, url): "ssl",
        executor.submit(check_whois, url): "whois",
        executor.submit(check_dns, url): "dns",
        executor.submit(check_redirects, url): "redirects",
    }
    for future in as_completed(futures):
        key = futures[future]
        results[key] = future.result()

# Heuristic checks (no I/O — instant)
results["tld"] = check_tld(url)
results["homograph"] = check_homograph(url)
results["brand"] = check_brand_impersonation(url)
# ...

return scoring.compute(results)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Total analysis time on most URLs: under 2 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Scoring Engine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;scoring.py takes the raw results and computes the final score. Each signal has a weight based on its phishing correlation strength:&lt;br&gt;
python# scoring.py (simplified)&lt;br&gt;
WEIGHTS = {&lt;br&gt;
    "suspicious_tld": 18,&lt;br&gt;
    "brand_impersonation": 25,&lt;br&gt;
    "homograph": 15,&lt;br&gt;
    "no_ssl": 13,&lt;br&gt;
    "recently_registered": 20,  # &amp;lt; 30 days&lt;br&gt;
    "direct_ip": 22,&lt;br&gt;
    "url_shortener": 10,&lt;br&gt;
    "double_extension": 15,&lt;br&gt;
    "at_char": 12,&lt;br&gt;
    "non_standard_port": 8,&lt;br&gt;
    "excessive_encoding": 10,&lt;br&gt;
    "subdomain_depth": 8,&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;def compute(results: dict) -&amp;gt; dict:&lt;br&gt;
    score = 50  # neutral start&lt;br&gt;
    details = []&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for key, weight in WEIGHTS.items():
    if results.get(key):
        score += weight
        details.append(f"{DESCRIPTIONS[key]} (+{weight})")

# Legitimate signals reduce the score
if results.get("ssl_valid"):
    score -= 10
if results.get("domain_age_days", 0) &amp;gt; 365:
    score -= 12
# ...

score = max(0, min(100, score))
return { "score": score, "risk_level": get_level(score), "details": details }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The weights were calibrated manually against a dataset of known phishing URLs from PhishTank and legitimate domains. It's not ML — it's deliberate, transparent logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everything is accessible via a simple REST API:&lt;br&gt;
&lt;code&gt;curl -X POST https://snifurl.online/analyze \&lt;br&gt;
  -H "Content-Type: application/json" \&lt;br&gt;
  -d '{"url": "https://example.com"}'&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{&lt;br&gt;
  "url": "https://example.com",&lt;br&gt;
  "score": 12,&lt;br&gt;
  "risk_level": "SAFE",&lt;br&gt;
  "recommendation": "LEGITIMATE — No significant indicators",&lt;br&gt;
  "details": ["Known legitimate root domain (example.com) (-12)"],&lt;br&gt;
  "indicators": {&lt;br&gt;
    "uses_https": true,&lt;br&gt;
    "dns_exists": true,&lt;br&gt;
    "has_ip": false,&lt;br&gt;
    "suspicious_tld": null,&lt;br&gt;
    "recently_created": false,&lt;br&gt;
    "ssl_certificate": { "valid": true, "issuer_org": "DigiCert" },&lt;br&gt;
    "whois": { "age_days": 9862, "registrar": "..." }&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
You can integrate this into your own app, browser extension, or Slack bot to flag links before users click them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack &amp;amp; Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Backend → Python 3.11 / Flask&lt;br&gt;
Analysis engine → analyseur_url.py + scoring.py&lt;br&gt;
Network checks → dnspython, python-whois, ssl (parallel execution)&lt;br&gt;
Frontend → Vanilla HTML / CSS / JS&lt;br&gt;
Server → Vultr VPS / Ubuntu 22.04 / Nginx + Gunicorn&lt;/p&gt;

&lt;p&gt;No framework overhead on the frontend. The UI is intentionally lean — the value is in the analysis, not the interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run It Yourself&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git clone https://github.com/FreemenTech/Snifurl&lt;br&gt;
cd snifurl&lt;br&gt;
pip install -r requirements.txt&lt;br&gt;
python app.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open &lt;a href="http://localhost:5000" rel="noopener noreferrer"&gt;http://localhost:5000&lt;/a&gt; — that's it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few things I'm thinking about:&lt;/p&gt;

&lt;p&gt;Browser extension — flag URLs inline before you click&lt;br&gt;
Bulk analysis endpoint — scan a list of URLs in one request&lt;br&gt;
ML scoring layer — train a model on PhishTank data to complement the heuristics&lt;br&gt;
Redirect chain analysis — follow shorteners and score the final destination&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try It&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🔗&lt;a href="//snifurl.online"&gt;Website&lt;/a&gt;&lt;br&gt;
Paste a suspicious URL you've received recently .I'd be curious what score it gets. Drop it in the comments.&lt;br&gt;
And if you find a false positive or a phishing URL that slips through open an issue. That's how the weights get better.&lt;/p&gt;

&lt;p&gt;Built by &lt;strong&gt;Freemen HOUNGBEDJI&lt;/strong&gt; — MIT License&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>python</category>
    </item>
    <item>
      <title>🔥 Building Vigilo: A 15MB File Integrity Monitor That Outperforms OSSEC</title>
      <dc:creator>Freemen HOUNGBEDJI</dc:creator>
      <pubDate>Fri, 06 Feb 2026 13:37:21 +0000</pubDate>
      <link>https://forem.com/freemen_tech/building-vigilo-a-15mb-file-integrity-monitor-that-outperforms-ossec-5g02</link>
      <guid>https://forem.com/freemen_tech/building-vigilo-a-15mb-file-integrity-monitor-that-outperforms-ossec-5g02</guid>
      <description>&lt;p&gt;🚨 The Night Everything Broke&lt;br&gt;
My former employer got hacked.&lt;/p&gt;

&lt;p&gt;At 3:07 AM, an attacker modified /etc/sudoers.&lt;br&gt;
No alerts.&lt;br&gt;
No logs reviewed.&lt;br&gt;
No alarms.&lt;/p&gt;

&lt;p&gt;We noticed it 3 days later.&lt;br&gt;
That night, I opened a blank Python file:&lt;br&gt;
   file_monitoring.py&lt;br&gt;
That file became Vigilo.&lt;/p&gt;

&lt;p&gt;❌ Why Existing Tools Failed Us&lt;br&gt;
We didn’t ignore security tools.&lt;br&gt;
We tried them.&lt;/p&gt;

&lt;p&gt;OSSEC&lt;br&gt;
❌ 200+ MB RAM on idle&lt;br&gt;
❌ 50+ lines of XML config for a single file&lt;br&gt;
❌ False positives drowning real alerts&lt;/p&gt;

&lt;p&gt;Wazuh&lt;br&gt;
❌ 30+ minutes installation&lt;br&gt;
❌ YAML + agents + dashboards&lt;br&gt;
❌ Massive overkill for &amp;lt; 50 servers&lt;/p&gt;

&lt;p&gt;What we needed was simple:&lt;/p&gt;

&lt;p&gt;“Tell me immediately when a critical file changes.&lt;br&gt;
Nothing more. Nothing less.”&lt;/p&gt;

&lt;p&gt;🛠️ What I Built Instead&lt;/p&gt;

&lt;p&gt;Vigilo is a lightweight File Integrity Monitor built for real-world ops teams.&lt;/p&gt;

&lt;p&gt;💾 &amp;lt; 15 MB RAM&lt;br&gt;
⚡ &amp;lt; 1 second alert latency&lt;br&gt;
🧠 Zero configuration hell&lt;br&gt;
🐍 100% Python, easy to hack &amp;amp; extend&lt;/p&gt;

&lt;p&gt;🎯 Core Design Principles&lt;/p&gt;

&lt;p&gt;Install in under 60 seconds&lt;br&gt;
Minimal memory footprint&lt;br&gt;
Readable, auditable code&lt;br&gt;
Production-ready from day one&lt;/p&gt;

&lt;p&gt;🧩 Technical Architecture&lt;br&gt;
vigilo/&lt;br&gt;
├── file_monitoring.py   # SHA-256 + metadata tracking&lt;br&gt;
├── FileWatcher.py       # inotify wrapper with smart filtering&lt;br&gt;
├── logger.py            # thread-safe persistent storage&lt;br&gt;
├── alert_manager.py     # system / future email / webhook alerts&lt;br&gt;
└── main.py              # CLI entrypoint&lt;/p&gt;

&lt;p&gt;⚡ Performance Optimizations That Matter&lt;br&gt;
1️⃣ In-Memory Baseline Cache&lt;br&gt;
Before (slow, disk-bound):&lt;br&gt;
def handle_event(path):&lt;br&gt;
    baseline = read_from_disk(path)&lt;/p&gt;

&lt;p&gt;After (fast, O(1)):&lt;br&gt;
def handle_event(path):&lt;br&gt;
    baseline = self.cache[path]&lt;br&gt;
📈 Result: 10× faster event processing.&lt;/p&gt;

&lt;p&gt;2️⃣ Atomic Writes (No Corrupted State)&lt;br&gt;
temp = "file_info.json.tmp"&lt;br&gt;
write_to(temp)&lt;br&gt;
os.replace(temp, "file_info.json")  # POSIX atomic&lt;/p&gt;

&lt;p&gt;Even a crash won’t break your baseline.&lt;/p&gt;

&lt;p&gt;3️⃣ Thread Safety (Because Events Are Brutal)&lt;br&gt;
_db_lock = threading.Lock()&lt;br&gt;
with _db_lock:&lt;br&gt;
    save_state()&lt;br&gt;
No race conditions. No silent corruption.&lt;/p&gt;

&lt;p&gt;📊 Benchmarks&lt;/p&gt;

&lt;p&gt;Test: Monitoring /etc/nginx/nginx.conf&lt;br&gt;
Load: 10 modifications / second&lt;/p&gt;

&lt;p&gt;Tool    CPU RAM False Positives&lt;br&gt;
Vigilo  0.8%    11 MB   0&lt;br&gt;
OSSEC   3.2%    187 MB  14&lt;br&gt;
Wazuh   5.1%    243 MB  23&lt;/p&gt;

&lt;p&gt;🚀 Usage&lt;/p&gt;

&lt;h1&gt;
  
  
  Install
&lt;/h1&gt;

&lt;p&gt;pip install -r requirements.txt&lt;/p&gt;

&lt;h1&gt;
  
  
  Add file to monitoring
&lt;/h1&gt;

&lt;p&gt;vigilo add /etc/nginx/nginx.conf --preset full --alert system&lt;/p&gt;

&lt;h1&gt;
  
  
  Start monitoring
&lt;/h1&gt;

&lt;p&gt;vigilo start&lt;br&gt;
Modify the file → desktop alert in &amp;lt; 1 second.&lt;/p&gt;

&lt;p&gt;🔐 Security First (Yes, Even the Tool)&lt;/p&gt;

&lt;p&gt;✅ Path whitelisting (no /etc/shadow)&lt;br&gt;
✅ Command injection protection (shlex.quote)&lt;br&gt;
✅ Strict file permissions (0o600)&lt;br&gt;
✅ Input validation on all CLI arguments&lt;/p&gt;

&lt;p&gt;🌙 Lessons Learned (The Hard Way)&lt;/p&gt;

&lt;p&gt;Night 1 — The Watchdog Spam&lt;br&gt;
One file triggered 1000+ events/min.&lt;br&gt;
👉 Fixed by filtering events before processing.&lt;/p&gt;

&lt;p&gt;Night 2 — The Performance Breakthrough&lt;br&gt;
Added in-memory cache.&lt;br&gt;
👉 Everything became 10× faster.&lt;/p&gt;

&lt;p&gt;Night 3 — The Security Obsession&lt;br&gt;
Found a command injection flaw in alert execution.&lt;br&gt;
👉 6 hours replacing everything with shlex.quote().&lt;/p&gt;

&lt;p&gt;Worth it.&lt;/p&gt;

&lt;p&gt;❌ When NOT to Use Vigilo&lt;br&gt;
You manage 1000+ servers&lt;br&gt;
You need advanced event correlation&lt;br&gt;
You require enterprise SLAs&lt;br&gt;
You must meet strict compliance (→ use Tripwire / Wazuh)&lt;br&gt;
✅ When Vigilo Is Perfect:&lt;br&gt;
&amp;lt; 100 servers&lt;br&gt;
You want something that just works&lt;br&gt;
You hate false positives&lt;br&gt;
You like tools you can actually read and modify&lt;/p&gt;

&lt;p&gt;🌍 Open Source&lt;br&gt;
🔗 GitHub: &lt;a href="https://github.com/FreemenTech/Vigilo" rel="noopener noreferrer"&gt;https://github.com/FreemenTech/Vigilo&lt;/a&gt;&lt;br&gt;
📄 License: MIT&lt;br&gt;
Contributions are welcome 🙌&lt;br&gt;
💬 Questions or feedback? Drop them below 👇&lt;/p&gt;

</description>
      <category>python</category>
      <category>cybersecurity</category>
      <category>opensource</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
