Aim
Phishing attacks are evolving rapidly, moving past basic email templates into highly targeted, encrypted message streams.
To solve this, I built PhishForensics PRO using Python, and hosted it directly on Hugging Face Spaces. It acts as a specialized toolkit for deep packet inspection, allowing security analysts and developers to paste raw message streams and immediately extract underlying threat vectors.
The primary aim of PhishForensics PRO is to bridge a critical gap in modern cybersecurity by decrypting raw, encrypted message streams on the fly to inspect them for hidden phishing indicators. By focusing heavily on the reverse-engineering and decryption of obfuscated payloads, the suite exposes hidden text vectors and subjects them to immediate, multi-layered forensic analysis.
Introduction
Modern threat actors rarely send plaintext phishing links anymore; instead, they hide malicious payloads inside encrypted data packets, obfuscated scripts, or encoded message streams to bypass perimeter defenses. Standard security filters are blind to these payloads because they cannot read the encrypted text.
To tackle this problem, I built PhishForensics PRO using Python. It provides security analysts with a powerful interface to input raw, encrypted payload streams, execute real-time decryption via deep packet inspection, and instantly feed the resulting plaintext into an automated threat intelligence pipeline.
The Technical Breakdown
The Decryption Pipeline & Core Architecture
Everything in PhishForensics PRO starts at the ingestion point. Once an encrypted message stream is pasted, the tool runs a dedicated decryption module to normalize the text before handing it off to the Hybrid NLP + Heuristic Analysis engine:
-
NLP Classifier: This engine scans the decrypted text using a Multinomial Naive Bayes machine learning algorithm (via
scikit-learn) to calculate a malicious intent score. -
Brand Protection: This uses the Levenshtein Distance algorithm to count character edits, flagging lookalike brand typosquatting (like
paypa1.cominstead ofpaypal.com).
Testing & Edge Cases
During testing, I found that while the NLP engine successfully flagged a sample text with a 93.3% threat score, the heuristic Brand Protection metric registered 0 spoofs.
This happened because the URL parser isolated micros0ft(with a zero). In my next code iteration, I plan to add a pre-processing text normalizer to convert common character substitutions (like '0' to 'o', or '1' to 'l') before passing strings into the Levenshtein Distance algorithm. This will make the deterministic checks just as robust as the machine learning engine. -
DGA Detection: This module calculates Shannon Entropy math to measure text randomness, helping it catch automatically generated hacker domains (like
x7z9q2w.com).
-
Stream Decryption Core: This entry layer parses and decodes scrambled or encrypted text streams back into clean, human-readable text for analysis.
- Stylometry: This checks writing structures using Feature Vector Extraction to analyze grammatical patterns and flag identity spoofing or fake sender styles.
Key Features
- On-the-Fly Stream Decryption: Converts obfuscated or encrypted payloads into structured text in real-time.
- Deep Packet Inspection Tooling: A seamless "one-click" workflow designed specifically to handle raw protocol streams.
- Parallel Modular Scoring: Instantly breaks down security risks across four distinct dimensions immediately after decryption.
The Problem:
Trying to decode broken data packets or unknown, mixed encodings without crashing the Streamlit app mid-run.
Solution:
This is handled by implementing a layered, nested try-except fallback logic block. The application first attempts a primary Base64 UTF-8 decode, if that fails, it instantly falls back to a hexadecimal byte-decryption pipeline. If both fail, it catches the exception safely and outputs an inline Streamlit error notification rather than letting the entire application crash or freeze.
Conclusion
PhishForensics PRO proves that security teams cannot rely on basic text filters when payloads are hidden behind layers of encryption. By prioritizing decryption right at the ingestion layer, this tool unmasks hidden threats so that Python-driven heuristic models can neutralize them before they reach an end user.
Future Challenge: Conversational Phishing Blindspots

When testing a highly conversational, friendly email structure (social engineering), the platform hit an architectural limitation. The engine scored the attack as an 8.0% Low Risk message.
Because the text used organic, casual corporate terminology rather than high-urgency panic words, the statistical NLP classifier was completely bypassed. Furthermore, because the attack relied entirely on human manipulation rather than chaotic technical layouts, the structural metrics (Entropy, Spoof counters) remained at zero.
To patch this in V2, I plan to:
- Incorporate LLMs: Move from a Naive Bayes classifier to an OpenAI API or fine-tuned BERT model capable of understanding deep conversational context and manipulation tactics.
- Hardcode Link Mandates: Upgrade the scoring logic so that any message containing an unverified link from an outside sender automatically accumulates risk points, regardless of how friendly the text sounds.
Future Roadmap
- Improving Predictive Accuracy: Acknowledging that no security system is 100% accurate, I plan to continuous optimize the detection thresholds and refine the underlying codebase to reduce false-positive rates.
- Sourcing Better Datasets: Expanding the machine learning model's training pipeline with larger, production-grade cybersecurity datasets (like live PhishTank threat feeds) to track modern, evolving obfuscation patterns.
- Expanding the Decryption Module: Supporting advanced custom cryptographic algorithms and custom ciphers.
Automating the Pipeline: Upgrading the system architecture to accept direct, live network traffic feeds instead of relying on manual copy-pasting.
Expanding the decryption module to support advanced custom cryptographic algorithms and custom ciphers.
Automating the pipeline to accept direct live network traffic feeds rather than manual copy-pasting.
💬 Let's Connect!
How do you handle the inspection of encrypted traffic or obfuscated text in your security workflows? Let's discuss in the comments!
import streamlit as st
import joblib
import re
import math
from urllib.parse import urlparse
import neattext.functions as nfx
from Levenshtein import distance as lev_dist # You'll need to add 'python-levenshtein' to requirements.txt
# 1. LOAD MODELS
model = joblib.load('phishing_model_v2.pkl')
tfidf = joblib.load('tfidf_vectorizer_v2.pkl')
# 2. BRAND PROTECTION LOGIC
PROTECTED_BRANDS = ['paypal', 'google', 'microsoft', 'netflix', 'amazon', 'apple', 'facebook']
# --- ADD THESE BACK ---
def calculate_entropy(text):
if not text: return 0
entropy = 0
for x in range(256):
p_x = float(text.count(chr(x)))/len(text)
if p_x > 0:
entropy += - p_x * math.log(p_x, 2)
return round(entropy, 2)
def forensic_url_scan(text):
url_pattern = r'https?://[^\s<>"]+|www\.[^\s<>"]+'
urls = re.findall(url_pattern, text)
reports = []
for u in urls:
hostname = urlparse(u).hostname or ""
entropy = calculate_entropy(u)
reports.append({
"URL": u,
"Entropy Score": entropy,
"Is_IP": 1 if hostname.replace('.', '').isdigit() else 0,
"Length": len(u)
})
return reports
# -----------------------
def check_brand_spoofing(text):
urls = re.findall(r'https?://[^\s<>"]+|www\.[^\s<>"]+', text.lower())
spoofs = []
for u in urls:
domain = urlparse(u).netloc
for brand in PROTECTED_BRANDS:
# If brand name is in the domain but it's not the official domain
if brand in domain and domain != f"{brand}.com":
# Calculate how close it is (Levenshtein Distance)
d = lev_dist(domain.split('.')[0], brand)
if d <= 2: # Very close typo
spoofs.append(f"Potential {brand.capitalize()} Impersonation ({domain})")
return spoofs
# 3. LINGUISTIC VECTOR ANALYSIS
def get_linguistic_metrics(text):
metrics = {}
metrics['Urgency'] = len(re.findall(r'(urgent|immediately|now|expire|suspended|action)', text.lower()))
metrics['Sensationalism'] = text.count('!') + text.count('$')
metrics['Length'] = len(text)
return metrics
# 4. ADVANCED UI
st.set_page_config(page_title="PhishForensics PRO", layout="wide")
st.title("🛡️ PhishForensics PRO: Multi-Vector Security Suite")
st.write("System Status: **Active** | Engine: **Hybrid NLP + Heuristic Analysis**")
col1, col2 = st.columns([2, 1])
with col1:
email_input = st.text_area("🔴 Paste Encrypted/Raw Message Stream:", height=250)
scan_btn = st.button("⚡ EXECUTE DEEP PACKET INSPECTION")
with col2:
st.markdown("""
### **Technical Modules**
- **NLP Classifier:** Multinomial Naive Bayes
- **DGA Detection:** Shannon Entropy Math
- **Brand Protection:** Levenshtein Distance
- **Stylometry:** Feature Vector Extraction
""")
if scan_btn and email_input:
# A. NLP Brain
clean = nfx.remove_special_characters(email_input.lower())
prob = model.predict_proba(tfidf.transform([clean]))[0][1] * 100
# B. Metadata & Brand Check
spoofs = check_brand_spoofing(email_input)
metrics = get_linguistic_metrics(email_input)
# C. RESULTS DASHBOARD
# C. RESULTS DASHBOARD
st.divider()
res1, res2, res3, res4 = st.columns(4) # Changed from 3 to 4 columns
res1.metric("Neural Threat Score", f"{prob:.1f}%")
# Calculate Max Entropy from the URL scan
url_reports = forensic_url_scan(email_input)
max_entropy = max([u['Entropy Score'] for u in url_reports], default=0)
res2.metric("Technical Entropy", max_entropy)
res3.metric("Urgency Markers", metrics['Urgency'])
res4.metric("Brand Spoofs", len(spoofs))
# Updated logic to include Entropy as a trigger
if prob > 75 or spoofs or max_entropy > 4.5:
st.error("### 🚨 HIGH-LEVEL THREAT DETECTED")
if max_entropy > 4.5:
st.warning(f"🚩 CRITICAL: High URL Entropy detected ({max_entropy}). The link structure looks obfuscated.")
for s in spoofs: st.warning(f"🚩 {s}")
else:
st.success("### ✅ MESSAGE VALIDATED: LOW RISK")
# D. LINGUISTIC RADAR (BAR CHART)
st.write("---")
st.write("### 📊 Stylometric Feature Map")
# This creates the visual representation of your linguistic metrics
st.bar_chart(metrics)
# E. TECHNICAL EVIDENCE TABLE (Optional but highly recommended for Engineering)
if url_reports:
st.write("### 📜 Technical URL Metadata")
st.dataframe(url_reports, use_container_width=True)
# --- ADD TO BOTTOM OF SCRIPT ---
st.write("---")
with st.expander("🔓 Advanced Utility: Message Deobfuscator"):
st.info("Use this to decode suspicious strings found in raw email code (Base64/Hex).")
encoded_input = st.text_input("Enter encoded string:")
if encoded_input:
import base64
try:
decoded = base64.b64decode(encoded_input).decode('utf-8')
st.code(decoded, language="text") # Using st.code makes it easy to copy
except:
try:
decoded = bytes.fromhex(encoded_input).decode('utf-8')
st.code(decoded, language="text")
except:
st.error("Invalid encoding format.")

Top comments (0)