Proof of concept
An intelligent phishing detection system that combines sender identity scoring, link reputation via VirusTotal, and LLM-based intent analysis into a single pipeline.
Keys Feature: Intent (Emotion) Analysis, Data privacy
This project is in its initial POC/MVP state. It explores how combining sentiment analysis with threat intelligence context data can be leveraged for security analysis. Future development plans include…
Phishia analyses emails and returns a structured verdict (malicious / benign) with a confidence score and a plain-language explanation. It works on .eml files, raw email strings or screenshots processed through OCR*.
Detection techniques:
- Levenshtein-based sender identity scoring + SPF record validation
- VirusTotal link reputation (submit → poll with in-memory cache)
- Cloudflare Intel domain categorisation (optional)
- LLM intent analysis with structured JSON output
- Tesseract OCR for image/screenshot inputs
Privacy-preserving by design: The LLM never receives the raw email. Phishia extracts only the relevant signals — sender metadata, link reputation scores, structural indicators — and feeds a structured feature summary to the model. Email body text and attachments stay local; only anonymized context is passed to external services.
Input
─────
.eml file ──► analyze_eml_parallel() ─┐
raw strings ──► analyze_raw_email() ─┤──► _analyze_email_data()
image/OCR ──► analyze_image() ─┘
│
┌─────────────────────────────────┤
│ |
| [Context enrichment]
▼ _________|
LLM |
[Intent analysis] |
analyse_link_objects(). |
┌─────────────────┐ └──► VirusTotal lookup
│ extract_text_ │ └──► Phone / Mailto checks
│ features() │ └──► Cloudflare category
│ │ │
│ get_text_ │ │
│ intention() │ summarise_reports()
└─────────────────┘ │
│ │
▼ ▼
normalize_intent_labels() get_sender_identity_score()
│ └──► Levenshtein similarity
│ └──► SPF-aware domain match
│ └──► keyword presence score
│ |
| [Data anonymization] │
└──────────────┬──────────────────┘
│
▼
get_interpretation_verdict()
LLM final verdict
│
▼
parse_ai_final_response()
│
▼
{ verdict, confidence, reason, conclusion }
Prerequisites: Python 3.8+, Tesseract OCR, at least one AI API key.
# 1. Clone
git clone https://github.com/yourusername/phishia.git
cd phishia
# 2. Install Tesseract
sudo apt-get install tesseract-ocr
# 3. Install Python dependencies
pip install -r requirements.txtRequired API keys:
- VirusTotal — link reputation
- Google Gemini / OpenAI — AI verdict
- Cloudflare — domain category (optional)
Config files live in assistant/configs/. Copy the closest template and fill in your keys.
[Logs]
LOG_DIR = logs
[VirusTotal]
VIRUSTOTAL_API_KEY = <YOUR_VIRUSTOTAL_API_KEY>
[Cloudflare]
; Optional — remove or leave blank to disable domain-category lookups
CLOUDFLARE_ACCOUNT_ID = <YOUR_CLOUDFLARE_ACCOUNT_ID>
CLOUDFLARE_API_TOKEN = <YOUR_CLOUDFLARE_API_TOKEN>
[AiModel]
; AI_MODE: 'online' for Gemini/ChatGPT, 'offline' for local Ollama
AI_MODE = online
AI_NAME = gemini-2.0-flash
API_KEY = <YOUR_API_KEY>
AI_URL = https://generativelanguage.googleapis.com/v1beta/models/{AI_NAME}:generateContent?key={API_KEY}| Config file | Backend |
|---|---|
phishia-gemini.ini |
Google Gemini |
phishia-chatgpt.ini |
OpenAI ChatGPT |
phishia-deepseek1.8b.ini |
DeepSeek via Ollama (offline) |
phishia.ini |
Default / Ollama |
curl -fsSL https://ollama.com/install.sh | sh
ollama pull deepseek-r1:14b
ollama serve[AiModel]
AI_MODE = offline
AI_URL = http://localhost:11434/api/generate
AI_NAME = deepseek-r1:14b
API_KEY = <NOT_REQUIRED_FOR_OFFLINE>from assistant.core import PhishiaCore
p = PhishiaCore("assistant/configs/phishia-gemini.ini")# Sequential (simpler)
result = p.analyze_eml("assistant/emls/legit_eu.eml")
# Parallel extraction (faster on large files)
result = p.analyze_eml_parallel("assistant/emls/vacanta.eml")result = p.analyze_raw_email(
sender_email={"alias": "Support", "email": "support@bank.com", "domain": "bank.com"},
_subject="Verify your account",
body="Click here to confirm your password...",
)result = p.analyze_image("path/to/screenshot.png"){
"verdict": "malicious",
"confidence": 0.91,
"reason": "Sender domain mismatch; 2 VirusTotal detections on embedded link.",
"conclusion": "This email is likely a phishing attempt targeting your credentials."
}# All unit tests — no API keys required
./run_tests.sh
# Unit + integration tests (requires a valid config)
./run_tests.sh --config assistant/configs/phishia-gemini.ini
# Single EML integration test
./run_tests.sh --config assistant/configs/phishia-gemini.ini --eml assistant/emls/vacanta.emlUnit tests cover all backend modules without network calls (VirusTotal and SPF are mocked):
| Test file | Module covered |
|---|---|
2_test_ocr.py |
OCRExtractor |
3_test_feature_extractor.py |
FeaturesExtractor / email_parser.py |
4_test_feature_analyser.py |
AnalyseFeatures / sender_analyser.py |
5_test_url_analyser.py |
LinkAnalyser / link_analyser.py |
6_test_utility_and_ai.py |
utility.py + AIInterpreter (non-API methods) |
phishia/
├── assistant/
│ ├── core.py # Orchestrator — entry point for all analysis
│ ├── utility.py # Config loading, result logging, response parsing
│ │
│ ├── backend/
│ │ ├── ai_interpreter.py # LLM abstraction (Gemini · ChatGPT · Ollama)
│ │ ├── email_parser.py # EML parsing, text/link extraction, OCR text cleaning
│ │ ├── sender_analyser.py # Sender identity scoring, SPF lookups
│ │ ├── link_analyser.py # VirusTotal, Cloudflare Intel, phone/mailto checks
│ │ ├── ocr_extractor.py # Tesseract OCR for screenshot/image input
│ │ ├── email_reporter.py # SMTP reporting helper
│ │ ├── prompt_builder.py # Loads prompt_config.yaml; print_log helper
│ │ └── prompt_config.yaml # Edit this to tune prompts or intent labels
│ │
│ ├── configs/
│ │ ├── phishia.ini
│ │ ├── phishia-chatgpt.ini
│ │ ├── phishia-gemini.ini
│ │ └── phishia-deepseek1.8b.ini
│ │
│ ├── emls/ # Sample .eml files for testing
│ │
│ └── tests/
│ ├── 1_test.py # Integration tests (requires API keys + --config)
│ ├── 2_test_ocr.py
│ ├── 3_test_feature_extractor.py
│ ├── 4_test_feature_analyser.py
│ ├── 5_test_url_analyser.py
│ └── 6_test_utility_and_ai.py
│
├── run_tests.sh # Test runner script
├── requirements.txt
├── pytest.ini
└── README.md
| File | Content |
|---|---|
logs/phishia.log |
Per-email verdict lines (timestamp · sender · result) |
logs/ai_prompt.log |
Full prompt + raw AI response for every call |
The logs/ directory is created automatically on first run. It is excluded from version control.
- Train custom LLM for intent analysis.
- Integrate with different vendors for context enrichment
- Docker image for self-hosted deployment
- Web dashboard to browse past analysis results and verdict history
- OCR functionality's implemented for image analysis
- SPF-only sender validation
- VirusTotal free-tier rate limit (4 requests/min) causes slowdowns on bulk runs
- No persistent cache across restarts — VirusTotal results are in-memory only
MIT — see LICENSE.
- VirusTotal — threat intelligence
- Google Gemini / OpenAI — language models
- Ollama — local model serving
- BeautifulSoup4 — HTML parsing
- Tesseract OCR — image text extraction
- python-Levenshtein — string similarity
- dnspython — SPF record resolution