PhishLens

Backend CI Extension CI Security CI codecov

Project site · Architecture · Privacy policy · Threat model · ML methodology · Demo script

PhishLens is a defensive Chrome extension and FastAPI backend for explainable phishing risk analysis in real time.

It combines local URL heuristics, privacy-preserving DOM signals, optional PhishTank threat intelligence, backend-side TLS certificate inspection, and an optional machine learning model. The project is built as a practical cybersecurity portfolio project with clear safety boundaries.

PhishLens flagging a fake PayPal login on a look-alike domain: a "Dangerous" risk score of 92 with an explained breakdown — look-alike domain, recent registration, and a password form posting to a non-brand domain

PhishLens catching a look-alike PayPal login (paypa1-secure-login.com) and explaining exactly why it is dangerous. End-to-end walkthrough:

PhishLens end-to-end demo: a safe page, a suspicious page, and a dangerous page triggering the warning overlay

Quick Start

# 1. Clone and set up the backend
git clone https://github.com/JuanCardesa/PhishLens.git && cd PhishLens
cp .env.example .env
python -m venv .venv && source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -r backend/requirements-dev.txt

# 2. Start the backend
uvicorn app.main:app --app-dir backend --reload

# 3. Build the extension
cd extension && npm install && npm run build

# 4. Load the extension in Chrome: chrome://extensions → Developer mode → Load unpacked → select extension/dist

# 5. (Optional) Build a real ML dataset and retrain the model
python ml/datasets/build_dataset.py && python ml/train_model.py

Current Status

Screenshots

Safe result Suspicious result Dangerous result
Safe result Suspicious result Dangerous result
Local-only mode (backend unavailable) Danger overlay
Local-only mode Danger overlay

Architecture

Chrome page
  -> content script extracts non-sensitive DOM signals
  -> popup computes local heuristic score
  -> popup optionally calls FastAPI /analyze
  -> backend adds URL, threat intel, TLS, and ML signals
  -> popup shows score, label, confidence, risk breakdown, and feedback controls
  -> dangerous results can display a dismissible page overlay
  -> development diagnostics expose counters only

The extension never sends full HTML, form values, passwords, or typed emails. The backend receives only the current URL and technical DOM features.

Stack

Development Setup

Backend

Linux / macOS

python -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements-dev.txt
uvicorn app.main:app --app-dir backend --reload

Windows

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r backend/requirements-dev.txt
.\.venv\Scripts\python.exe -m uvicorn app.main:app --app-dir backend --reload

Health check:

curl http://localhost:8000/health

Interactive API documentation is available at http://localhost:8000/docs while the backend is running.

Extension

cd extension
npm install
npm run build

Load extension/dist in Chrome:

  1. Open chrome://extensions.
  2. Enable Developer mode.
  3. Select “Load unpacked”.
  4. Choose the extension/dist folder.

The extension works locally without the backend. When the backend is available at http://localhost:8000, the popup enriches the local result with backend analysis.

Extension settings are available from the popup settings button or Chrome extension details page. The default backend is http://localhost:8000.

Tests

Backend:

.\.venv\Scripts\python.exe -m pip install -r backend/requirements-dev.txt
pytest backend/tests

Extension:

cd extension
npm run lint
npm run test
npm run build
npm audit --audit-level=high

ML demo:

python ml/train_model.py
python ml/evaluate_model.py

Docker:

docker compose build
docker compose up backend

Review automation:

python scripts/ci/pr_guardian.py --all

Demo readiness:

python scripts/dev/check_demo.py

Configuration

Copy .env.example to .env for local overrides. No real keys are committed.

Variable Default Description
PHISHTANK_API_KEY (empty) Optional PhishTank application key. Omit to skip threat intel.
PHISHTANK_USER_AGENT phishtank/phishlens-demo User-Agent sent with PhishTank requests (required by their API).
PHISHLENS_ALLOWED_ORIGINS http://localhost:5173 Comma-separated CORS origins. Add chrome-extension://* only for local dev.
PHISHLENS_CHROME_EXTENSION_IDS (empty) Comma-separated Chrome extension IDs for production CORS.
PHISHLENS_ENABLE_THREAT_INTEL true Enable/disable PhishTank lookups.
PHISHLENS_ENABLE_TLS_ANALYSIS true Enable/disable backend TLS certificate inspection.
PHISHLENS_ENABLE_CT_LOG_LOOKUP true Enable/disable Certificate Transparency log lookups (crt.sh) as an additional TLS risk signal.
PHISHLENS_ENABLE_DOMAIN_AGE_LOOKUP true Enable/disable RDAP domain-registration-age lookups.
PHISHLENS_EXTERNAL_TIMEOUT_SECONDS 4.0 Timeout for external backend enrichment calls such as PhishTank, RDAP, and crt.sh.
PHISHLENS_MODEL_PATH app/models/phishlens_model.joblib Path to a trained joblib model artifact.
PHISHLENS_BRAND_DOMAINS_PATH app/data/brand_domains.json Path to the curated brand-domain list used for typosquat/brand-impersonation detection.
PHISHLENS_ENABLE_DIAGNOSTICS true Expose aggregate counters at GET /diagnostics.
PHISHLENS_DIAGNOSTICS_TOKEN (empty) When set, GET /diagnostics requires X-Diagnostics-Token: <value>.
PHISHLENS_ENABLE_RATE_LIMITING true Enable in-memory sliding-window rate limits.
PHISHLENS_ANALYZE_RATE_LIMIT 60 Max /analyze requests per window per IP.
PHISHLENS_REPORT_RATE_LIMIT 20 Max /report requests per window per IP.
PHISHLENS_RATE_LIMIT_WINDOW_SECONDS 60 Rate-limit window in seconds.
PHISHLENS_BEHIND_PROXY false Trust X-Forwarded-For when behind nginx / Caddy / ALB.
PHISHLENS_FEEDBACK_DB_PATH feedback.db SQLite path for feedback metadata. Set to "" to disable.
PHISHLENS_ENABLE_DEMO_THREAT_SOURCE false Enable localhost-only dangerous demo signal.

Extension settings:

Ethical And Privacy Notice

PhishLens is defensive only. It must not collect credentials, typed emails, private form content, or full page HTML. It is a risk-assistance tool, not a phishing verdict authority. False positives and false negatives are expected, especially outside the limited dataset and signal coverage documented below.

Local Demo

Run the backend, demo pages, and extension locally:

$env:PHISHLENS_ENABLE_DEMO_THREAT_SOURCE="true"
.\.venv\Scripts\python.exe -m uvicorn app.main:app --app-dir backend --reload
python demo/serve_demo.py
cd extension
npm run build

Load extension/dist in Chrome and visit:

The dangerous demo requires PHISHLENS_ENABLE_DEMO_THREAT_SOURCE=true and only matches localhost URLs containing phishlens-demo-dangerous. Use localhost rather than 127.0.0.1: the backend rejects private IP literals as an SSRF safeguard.

Package the extension:

cd extension
npm run package

The zip is written to extension/release/.

Limitations

Lessons Learned

A few things found during a deliberate self-audit of this project, kept here instead of quietly fixed and forgotten, because how a bug was found and corrected is often more informative than the fact that the code is now clean:

Roadmap

See docs/roadmap.md.

Review And Release Process

PhishLens uses deterministic review gates instead of relying on a single reviewer. See docs/review-methodology.md and docs/release-process.md.

Publication preparation lives in docs/chrome-web-store.md, with permission rationale in docs/permissions.md.