PhishNet¶
Fast, local phishing analysis for suspicious emails, no external services required.
PhishNet parses .eml files and applies opinionated checks across headers, links, and attachments to surface spoofing indicators and risky artifacts. Results come out as a human-readable summary or machine-readable JSON. An optional web dashboard lets you upload and review findings in a browser.
Why¶
Email is the primary entry point for social engineering and malware delivery. Most analysis tools either require cloud API keys, send data to external services, or demand complex setup. PhishNet gives analysts and engineers quick, repeatable checks that run entirely offline: standard library parsing, no credentials, no network calls. Enrichment integrations (VirusTotal, PhishTank, Google Safe Browsing) are available but strictly opt-in.
Features¶
- Header analysis: detects spoofing indicators via Return-Path mismatches and authentication failures
- Link inspection: flags URL shorteners, punycode, IP-address URLs, and known suspicious domains
- Attachment checks: catches dangerous file extensions and emits SHA-256 hashes for downstream lookup
- Dual output modes: human-readable summary or structured JSON for automation pipelines
- Opt-in enrichment: integrates with VirusTotal, PhishTank, and Google Safe Browsing when API keys are configured
- Web dashboard: browser-based upload and review interface showing findings and parsed headers
- Minimal footprint: standard library for all parsing;
flaskonly required for the dashboard
Installation¶
git clone https://github.com/Skellman-io/PhishNet.git
cd PhishNet
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
Quick Start¶
# Analyze an .eml file — human-readable output
python -m phishnet.cli analyze ./examples/suspicious.eml --format summary
# Analyze an .eml file — JSON output for automation
python -m phishnet.cli analyze ./examples/suspicious.eml --format json
# Analyze with enrichment lookups enabled (requires configured API keys)
python -m phishnet.cli --enrich analyze ./examples/suspicious.eml
# Launch the web dashboard
python -m phishnet.dashboard
# Then open http://127.0.0.1:5000
Options¶
| Flag | Description | Default |
|---|---|---|
--format |
Output format: summary or json |
summary |
--enrich |
Enable external enrichment lookups (PhishTank, VirusTotal, Google Safe Browsing) | off |
Checks¶
Headers¶
| Check | Severity | What it catches |
|---|---|---|
| Return-Path domain mismatch | HIGH | From domain differs from Return-Path domain, a common spoofing indicator |
| SPF / DKIM / DMARC failures | HIGH | Authentication-Results showing fail or softfail |
| Suspicious Reply-To | MEDIUM | Reply-To domain differs from sender domain |
Links¶
| Check | Severity | What it catches |
|---|---|---|
| IP-address URLs | HIGH | Links using raw IP addresses instead of domain names |
| Punycode domains | HIGH | Internationalized domains using xn-- encoding, a common homograph attack indicator |
| Known suspicious domains | HIGH | Domains matched against a local suspicious domain list |
| URL shorteners | MEDIUM | Links through shortener services that mask the true destination |
Attachments¶
| Check | Severity | What it catches |
|---|---|---|
| Dangerous file extensions | HIGH | Files ending in .exe, .js, .scr, .vbs, .docm, and similar |
| SHA-256 hash extraction | INFO | Hash emitted for every attachment; use for downstream VirusTotal or YARA lookups |
Output Formats¶
Human-readable output with severity labels. Default for analyst review:
Structured output for automation, SIEM ingestion, or custom reporting:
Enrichment Integrations¶
PhishNet supports optional enrichment lookups against external threat intelligence services. All integrations are disabled by default: no external calls are made unless explicitly enabled with an API key.
Configure integrations in phishnet_config.yaml at the project root:
enrichment:
phishtank:
enabled: false
api_key: "INSERT KEY HERE"
google_safebrowsing:
enabled: false
api_key: "INSERT KEY HERE"
virustotal:
enabled: false
api_key: "INSERT KEY HERE"
Then run with --enrich to activate configured lookups:
| Integration | What it enriches | Requires |
|---|---|---|
| PhishTank | Checks extracted URLs against known phishing database | Free API key |
| Google Safe Browsing | Flags URLs against Google's threat lists | GCP API key |
| VirusTotal | Looks up attachment SHA-256 hashes for malware hits | Free or paid API key |
Web Dashboard¶
Start the dashboard and open http://127.0.0.1:5000 in a browser:
Upload any .eml file to get:
- Findings panel: severity-coded list of all detected issues (HIGH in red, MEDIUM in amber, LOW in green)
- Parsed headers table: full header dump for manual inspection
The dashboard is intended for local analyst use. The default secret key is a placeholder; replace it before exposing the service on any shared network.
CI/CD Integration¶
GitHub Actions¶
name: PhishNet Sample Scan
on: [push, pull_request]
jobs:
phishnet:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install -r requirements.txt
- run: python -m phishnet.cli analyze ./examples/suspicious.eml --format json
GitLab CI¶
phishnet:
image: python:3.11-slim
script:
- pip install -r requirements.txt
- python -m phishnet.cli analyze ./examples/suspicious.eml --format summary
Exit Codes¶
| Code | Meaning |
|---|---|
0 |
No findings |
1 |
Findings present — review output |
2 |
Tool error (invalid file, parse failure) |
Requirements¶
- Python 3.9+
- Dependencies:
flask>=3.0.0(dashboard only; not required for CLI) - All parsing uses the Python standard library
Project Structure¶
phishnet/
├── __init__.py
├── cli.py
├── config.py
├── dashboard.py
├── analyzers/
│ ├── headers.py
│ ├── links.py
│ ├── attachments.py
│ └── utils.py
└── enrichment/
├── headers.py
├── links.py
└── attachments.py
examples/
phishnet_config.yaml
requirements.txt
MIT License — Copyright © 2026 Skellman.io