Skip to content

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.

View on GitHub


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; flask only 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
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:

[HIGH] links: IP-address URL detected: http://192.168.1.1/payload
[HIGH] headers: Return-Path domain mismatch: from=legit.com, return-path=attacker.net
[HIGH] attachments: Dangerous extension: invoice.docm
[MEDIUM] links: URL shortener detected: bit.ly/3xAmPl3

Structured output for automation, SIEM ingestion, or custom reporting:

{
  "findings": [
    {
      "severity": "HIGH",
      "component": "headers",
      "message": "Return-Path domain mismatch: from=legit.com, return-path=attacker.net"
    },
    {
      "severity": "HIGH",
      "component": "attachments",
      "message": "Dangerous extension: invoice.docm | SHA-256: a3f1c2..."
    }
  ]
}

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:

python -m phishnet.cli --enrich analyze ./suspicious.eml
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:

python -m phishnet.dashboard

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