Internship-26

πŸ›‘οΈ PhishGuard β€” URL Risk Analysis System

A Flask-based web application that analyses URLs through a seven-stage detection pipeline to classify them as Safe, Suspicious, or Malicious β€” and explains exactly why.


Table of Contents


Overview

PhishGuard analyses every URL through a multi-stage pipeline β€” from raw input all the way to a human-readable safety recommendation β€” so you know exactly why a link is flagged, not just that it was flagged.

It accepts input as:

Results include a full breakdown of URL structural features, contextual signals, weighted feature fusion scores, redirect chains, and a plain-English safety recommendation.


Features


Pipeline Architecture

The flowchart below describes the full processing pipeline:

User Input (URL or QR Code)
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 1            β”‚
β”‚  Input Detection    β”‚  ── URL text  OR  QR image β†’ decoded URL
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 2            β”‚
β”‚  Validate &         β”‚  ── Structural check, add scheme, lowercase host,
β”‚  Normalise          β”‚     strip tracking params (utm_*, fbclid, gclid…)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 3            β”‚
β”‚  Redirect           β”‚  ── Follow up to 5 HTTP hops to find final destination
β”‚  Resolution         β”‚     Records full redirect chain
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 4            β”‚  ── Domain entropy, suspicious TLDs, IP-address hosts,
β”‚  URL Feature        β”‚     brand in subdomain, Punycode/IDN, URL length,
β”‚  Extraction         β”‚     query param count, executable extensions, keywords…
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 5            β”‚  ── Cross-domain redirect chains, brand impersonation
β”‚  Contextual         β”‚     (e.g. "paypal" in URL but domain β‰  paypal.com),
β”‚  Analysis           β”‚     credential-harvest paths, HTTP on sensitive domains
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 6            β”‚  ── Weighted combination:
β”‚  Feature Fusion     β”‚     55% URL features + 45% contextual signals
β”‚  & Risk Scoring     β”‚     Hard-boost rules for definitive signals
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 7            β”‚  ── Safe (<35%) / Suspicious (35–65%) / Malicious (>65%)
β”‚  Classification &   β”‚     Plain-English safety recommendation with per-signal
β”‚  Recommendation     β”‚     explanations
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Stage Details

# Stage What it does
1 Input Detection Accepts a typed URL or a QR image. When an image is uploaded it is decoded via pyzbar to extract the embedded URL.
2 Validate & Normalise Checks structural validity. Adds https:// if missing, lowercases the host, removes default ports, strips common tracking parameters (utm_*, fbclid, gclid, msclkid, etc.).
3 Redirect Resolution Follows HTTP redirects (up to 5 hops) using a HEAD request with a browser-like User-Agent to find the true destination. The full redirect chain is stored and displayed.
4 URL Feature Extraction Extracts 15+ structural features: domain entropy, suspicious TLDs, raw-IP hosts, brand keywords in subdomain, Punycode/IDN homograph detection, URL length, query-parameter count, executable file extensions, hex-encoded characters, redirect patterns in path, and more.
5 Contextual Analysis Layers contextual signals on top: cross-domain redirect chains, brand impersonation detection (claimed brand vs. actual domain), credential-harvesting path patterns (/login, /verify, /account, etc.), and unencrypted HTTP on sensitive domains.
6 Feature Fusion & Risk Scoring Combines URL structural features (55% weight) and contextual signals (45% weight) into a single fused score. Hard-boost rules override the weighted score for definitive indicators (IP-based hosts, confirmed brand impersonation, executable links).
7 Safety Recommendation Maps the fused score to a classification and generates a plain-English recommendation, augmented with specific notes for each triggered signal (shortener detected, IP host, brand mismatch, executable link, etc.).

Risk Classification

Verdict Score Range Meaning
βœ… Safe < 35% No significant phishing indicators. Proceed with normal caution.
⚠️ Suspicious 35% – 65% Risk signals present. Verify independently before entering credentials.
🚨 Malicious > 65% Strong phishing / malware indicators. Avoid this link entirely.

Signals that trigger hard-boost rules

These bypass weighted scoring and force the fused score to a minimum threshold:

Signal Minimum fused score
Raw IP address as host 60%
Brand name in subdomain 65%
Confirmed brand impersonation 72%
Executable file extension (.exe, .bat, etc.) 78%
Trusted domain (no impersonation) capped at 25%

Tech Stack

Layer Technology
Web framework Flask 3.0.3
ORM / Database Flask-SQLAlchemy 3.1.1 + SQLite
Authentication Flask-Login 0.6.3
CSRF protection Flask-WTF 1.2.1
Password hashing Werkzeug 3.0.3
HTTP / redirect resolver requests 2.32.3
QR decoding pyzbar 0.1.9 + Pillow 10.4.0
Environment config python-dotenv 1.0.1
Frontend Vanilla JS + custom CSS design system

Project Structure

Internship-26/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ __init__.py          # Application factory β€” extensions + blueprint registration
β”‚   β”œβ”€β”€ auth.py              # Authentication blueprint (login / register / logout)
β”‚   β”œβ”€β”€ models.py            # SQLAlchemy models: User, ScanHistory
β”‚   β”œβ”€β”€ routes.py            # Main blueprint (about page)
β”‚   β”œβ”€β”€ scanner.py           # Core pipeline β€” all 7 stages + Flask routes
β”‚   β”œβ”€β”€ static/
β”‚   β”‚   β”œβ”€β”€ css/style.css    # Full design system + pipeline UI components
β”‚   β”‚   └── js/main.js       # Alerts, nav toggle, password show/hide, count-up
β”‚   └── templates/
β”‚       β”œβ”€β”€ base.html        # Master layout with navbar, flash messages, footer
β”‚       β”œβ”€β”€ about.html       # Pipeline documentation page
β”‚       β”œβ”€β”€ auth/
β”‚       β”‚   β”œβ”€β”€ login.html
β”‚       β”‚   └── register.html
β”‚       └── scanner/
β”‚           β”œβ”€β”€ dashboard.html   # Stats cards + recent scans
β”‚           β”œβ”€β”€ scan.html        # Tabbed URL / QR input form
β”‚           β”œβ”€β”€ result.html      # Full analysis breakdown
β”‚           └── history.html     # Full scan history list
β”œβ”€β”€ instance/
β”‚   └── app.db               # SQLite database (auto-created)
β”œβ”€β”€ config.py                # Config classes (Development / Testing / Production)
β”œβ”€β”€ run.py                   # Entry point β€” creates tables, seeds demo user, starts server
β”œβ”€β”€ requirements.txt
└── .env                     # Environment variables (not committed)

Key models

User

id, username (unique), email (unique), password_hash,
created_at, is_active
β†’ relationship: scans (ScanHistory)

ScanHistory

id, user_id (FK), url, original_url, input_type (url|qr),
prediction (safe|suspicious|malicious), probability (0.0–1.0),
risk_level (LOW|MEDIUM|HIGH), model_version,
recommendation (text), details_json (JSON blob),
scanned_at

The details_json column stores the full pipeline breakdown:

{
  "url_features":   { "domain": "...", "is_ip_address": false, ... },
  "context":        { "brand_mismatch": true, "num_redirects": 2, ... },
  "fusion":         { "fused_score": 0.74, "url_score": 0.68, ... },
  "redirect_chain": ["https://bit.ly/xxx", "https://evil.example.com"]
}

Setup & Installation

Prerequisites

1. Clone the repository

git clone <repo-url>
cd Internship-26

2. Create and activate a virtual environment

python -m venv venv

# Windows
venv\Scripts\activate

# macOS / Linux
source venv/bin/activate

3. Install dependencies

pip install -r requirements.txt

Note β€” QR code support: pyzbar requires the zbar shared library.

4. Configure environment variables

Copy .env.example to .env and set your values:

FLASK_APP=run.py
FLASK_ENV=development
SECRET_KEY=your-secret-key-here
DATABASE_URL=sqlite:///app.db

# Optional: point at a real ML detection service
# SCAN_API_URL=https://your-model-service.example.com/predict

Running the App

python run.py

On first run this will:

  1. Create all database tables
  2. Seed a demo user: demo@phishguard.io / demo1234
  3. Start the server at http://localhost:5000

Usage

Scanning a URL

  1. Log in at http://localhost:5000
  2. Go to Scan URL in the navbar
  3. Select the Enter URL tab, paste any URL, and click Scan URL
  4. The result page shows:
    • Verdict badge (Safe / Suspicious / Malicious)
    • Safety recommendation with per-signal notes
    • Risk probability score + progress bar
    • URL Feature Extraction β€” table of structural signals + flag chips
    • Contextual Analysis β€” brand impersonation, redirects, credential paths
    • Feature Fusion β€” weighted bar chart of how the final score was computed
    • Redirect Chain β€” each hop from the original URL to the final destination

Scanning a QR code

  1. Go to Scan URL and select the Upload QR Code tab
  2. Drag and drop a QR image onto the drop zone, or click to browse
  3. Click Decode & Scan QR β€” the URL is extracted and run through the same pipeline

Example URLs to test

URL Expected result
https://github.com βœ… Safe
https://secure-paypal-verify.xyz/login 🚨 Malicious
http://192.168.1.1/paypal-login-verify.exe 🚨 Malicious
https://login-amazon-account-update.tk 🚨 Malicious
https://en.wikipedia.org/wiki/Phishing βœ… Safe

API Reference

POST /api/scan

Scan a URL via JSON. CSRF-exempt β€” suitable for programmatic use.

Request

POST /api/scan
Content-Type: application/json

{ "url": "https://example.com/path" }

Response 200 OK

{
  "url": "https://example.com/path",
  "original_url": "https://example.com/path",
  "prediction": "safe",
  "probability": 0.08,
  "risk_level": "LOW",
  "model_version": "pipeline-v2",
  "recommendation": "This URL appears safe to visit...",
  "url_features": {
    "domain": "example.com",
    "tld": ".com",
    "is_ip_address": false,
    "is_trusted_domain": false,
    "has_suspicious_tld": false,
    "has_brand_in_subdomain": false,
    "url_length": 27,
    "domain_entropy": 2.807,
    "suspicious_keywords": [],
    "url_feature_score": 0.07
  },
  "context": {
    "num_redirects": 0,
    "crosses_domains": false,
    "brand_mismatch": false,
    "credential_path": false,
    "context_score": 0.0
  },
  "fusion": {
    "fused_score": 0.08,
    "url_weight": 0.55,
    "context_weight": 0.45,
    "url_score": 0.07,
    "context_score": 0.0
  },
  "redirect_chain": []
}

Error responses

Status Body Reason
400 {"error": "url field is required"} Missing url field
422 {"error": "invalid url"} URL fails structural validation

Configuration

Variable Default Description
SECRET_KEY change-me-in-production Flask session signing key
DATABASE_URL sqlite:///app.db SQLAlchemy database URI
SCAN_API_URL (empty) External ML model endpoint. When empty, the built-in pipeline is used.
FLASK_ENV development Enables debug mode when set to development
PORT 5000 Port the server listens on

When SCAN_API_URL is set, the app POSTs {"url": "<url>"} to that endpoint and expects a JSON response with at minimum prediction, probability, and risk_level fields.


Demo Credentials

Field Value
Email demo@phishguard.io
Password demo1234

Created automatically on first run. Change or remove in run.py β†’ seed_demo_user() before deploying.