~/posts/sih-2026-email-forensics
SIH 2026: AI Email Threat Detection & Forensic Intelligence
- sih-2026
- hackathon
- ai-ml
- security
- email-forensics
For Smart India Hackathon 2026, my team (AICTE problem statement) built a platform that attacks email threats from two directions at once: detect the bad email the moment it lands, and prove it with sender-level forensics that a security team can actually use.
This is the post-mortem — the stack, the pipeline, the real numbers, and what I'd do differently next time.
The problem
Phishing, business email compromise (BEC) and malware-laden email are still the cheapest, most effective way into an organization. Most filters only tell you "this is malicious, score: 87" — with no way to explain the verdict, see where the sender actually was, or export evidence for an incident report.
So the brief we chased was: detect it, explain it, and hand over forensics.
The pipeline
1. Detection — an adaptive ML ensemble (the real numbers)
We trained on 7 curated datasets totaling ~34,000 emails and leaned on an ensemble instead of a single model:
- XGBoost (400 trees, depth 7) — 97.39% accuracy, AUC 0.9957
- LightGBM (500 trees, 63 leaves) — 97.56% accuracy, AUC 0.9959
- DistilBERT (fine-tuned, 3 epochs) — 98.92% accuracy, AUC 0.9991
- Weighted fusion:
0.6·bert + 0.2·xgb + 0.2·lgbwhen BERT is available, falling back to0.5·xgb + 0.5·lgbwhen it isn't
The backend auto-detects whether DistilBERT is installed and degrades gracefully — the free-tier Render deployment runs XGB+LGB at ~200 MB RAM, the full ensemble needs the ~600 MB tier. Same API either way.
On top of 30,000 TF-IDF features (n-grams 1–3) we engineered 19 handcrafted signals — caps ratio, suspicious TLD detection, credential-harvesting phrase counts, urgency language, IP-in-URL flags — appended to the sparse matrix so the tree models see structure, not just vocabulary.
2. Training data — poisoning the poisoners
The dataset mix is the part I'm proudest of. Beyond the Kaggle corpora, we included 1,000 human-crafted phishing emails and 1,000 LLM-generated phishing emails (plus matching legitimate sets from both sources).
Why: classic keyword filters are trained on template phishing. Modern spear-phishing is written by LLMs — evasive, well-grammar'd, personalized. If your model has never seen AI-crafted attacks, it will bless them. Ours was trained on them.
(Also a lesson in data engineering: llm_phishing.csv had unquoted commas in
email text, so the Colab notebook ships a custom CSV parser that splits on the
last comma only — plus fixes for four deprecated PyTorch/NLTK/XGBoost API
calls.)
3. Intelligence fusion — a weighted six-signal risk score
A single model is easy to fool, so the risk score is a weighted composite of six signals (0–100): ML verdict, threat intel, email authentication, sender geolocation, forensic findings, and content analysis.
risk = 0
for source, weight in SOURCES: # VirusTotal, Safe Browsing,
risk += weight * source.score # PhishTank, RDAP, AbuseIPDB
risk = clamp(risk, 0, 100)
Each source contributes a weighted vote, so a URL that VirusTotal flags but Safe Browsing hasn't seen yet still moves the needle — just not as far as one everyone agrees on.
4. Forensics — the part filters never do
- Header forensics: SPF, DKIM and DMARC analysis on every email, plus a custom parser for the authentication results
- Sender geolocation: per-hop tracing of the
Receivedchain instead of trusting theFromheader — MaxMind GeoLite2 with an ipapi.co fallback - Live threat map (Leaflet.js) for the SOC view, and a threat-intel dashboard (Chart.js) tracking phishing trends, auth-failure rates and a country heatmap
- Two intake paths: scan a Gmail inbox via OAuth 2.0, or drag-and-drop a
.emlfile for analysis with zero credentials - PDF forensic reports (ReportLab) that read like evidence, not logs
5. Engineering hygiene
- 95 unit tests across the ML pipeline, forensic analyzer, and services — all synthetic data, no network, no models required
- Docker one-command deploy, plus
render.yamlwith auto-deploy - The dashboard ships as Jinja templates and an optional React + Vite +
TypeScript SPA that talks to the same Flask APIs (
FRONTEND_SPA=1/0) - LLM API enrichment for explainable classification on top of the score
Stack
Python · Flask · Flask-SocketIO · SQLAlchemy (SQLite) · scikit-learn · XGBoost · LightGBM · PyTorch/Transformers (DistilBERT) · LLM API · VirusTotal · Safe Browsing · AbuseIPDB · MaxMind GeoLite2 · ReportLab · Leaflet · Chart.js · React/Vite (optional SPA) · Docker · Render
My role: ML integration + architecture
I owned model training and the ML pipeline — dataset merging across 7 sources
with explicit column mapping, the feature-engineering layer, training all
three models on Colab T4s, and the ensemble's graceful-degradation logic that
lets the same codebase run on a free-tier VM or with full BERT depth. I also
wired the deployment path: models flow from Colab → Drive → backend/ml/models/
→ Render.
What I'd do differently
- Score explainability earlier. We added verdict explanations near the end; the demo landed harder once a user could see why an email scored 92.
- Lock the eval set on day one. Ensemble tuning burned hours we could have saved with a frozen benchmark.
- PDF generation is a rabbit hole. ReportLab is powerful, but it ate a full day — next time I'd prototype the report template before the model.
Links
- Repo: github.com/SabarishR08/mailforensic-ai
- Live dashboard: sih26106-email-forensics.onrender.com/dashboard
- Training datasets: Google Drive folder
- Colab training notebook: open in Colab
Sabarish R (ML integration + architecture) · Vignesh (geolocation) · Shafeeq (forensic intelligence) · Rohith (dashboard + demo).