File size: 5,509 Bytes
3303764
0318213
 
 
 
3303764
0318213
3303764
 
0318213
3303764
 
0318213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
---
title: ShadowSage AI
emoji: πŸ‘οΈ
colorFrom: purple
colorTo: indigo
sdk: gradio
sdk_version: "6.26.0"
app_file: app.py
pinned: false
license: mit
---

# ShadowSage AI β€” the all-seeing guardian of your digital world

An AI-powered cybersecurity oracle that defends **proactively**, not reactively.
ShadowSage detects hidden threats before they land, analyzes suspicious messages,
identifies phishing, uncovers your exposed digital footprint, and watches login
behavior for signs of account takeover β€” then distills everything into one
**Sage Score** with plain-English guidance.

Built for CPU-only live demos: small models, no API keys required, everything
degrades gracefully to a labeled fallback instead of crashing.

## The four scrying stones

| Tab | What it does | How |
| --- | --- | --- |
| **Sage Verdict** | One combined Sage Score + 2-3 personalized recommendations | Weighted average of the three module scores (formula in `utils/scoring.py`) |
| **Phishing Analyzer** | Risk score, verdict and highlighted evidence for any email / SMS / URL | DistilBERT fine-tuned on a bundled 284-example dataset **plus** transparent rule + URL heuristics (typosquats, raw-IP hosts, abuse TLDs, entropy, urgency patterns) |
| **Footprint Scanner** | Breach history + exposure score for an email or domain | HaveIBeenPwned API v3 when `HIBP_API_KEY` is set; otherwise a **clearly-labeled** deterministic demo dataset |
| **Behavior Monitor** | Login timeline with anomalies highlighted + behavioral risk score | Isolation Forest over `data/login_activity.csv` (90 days of synthetic history with 7 planted intrusions), features include circular hour encoding, rare country/device flags and impossible-travel velocity |

## Project structure

```
app.py                      # Gradio Blocks UI β€” the whole mystical dashboard
model/phishing_classifier.py # DistilBERT training + rule/URL fallback engine
model/behavior_monitor.py    # Isolation Forest behavioral monitor
utils/footprint_scanner.py   # HaveIBeenPwned v3 wrapper + demo fallback
utils/scoring.py             # Sage Score formula + recommendation engine
data/phishing_dataset.csv    # 284 labeled examples (1 = phishing)
data/login_activity.csv      # 130 login events, 7 planted anomalies
data/generate_login_data.py  # deterministic generator for the login history
```

## Run locally

```bash
python -m venv .venv
# Windows: .venv\Scripts\activate   |   macOS/Linux: source .venv/bin/activate
pip install -r requirements.txt
python app.py                # -> http://127.0.0.1:7860
```

On the very first launch there is no trained model yet, so the app starts in
**rule-engine mode** (fully functional) and fine-tunes DistilBERT in a
background thread β€” the Phishing tab shows the training status
("the Sage is awakening"). Analysis is never blocked.

## Deploy to Hugging Face Spaces

1. Create a new Space β†’ SDK: **Gradio**.
2. Push this repo as-is (`app.py` stays at the root; the YAML block at the top
   of this README is the Spaces config).
3. Done. `requirements.txt` installs everything; on first boot the Space trains
   the phishing model in the background and shows rule-based results meanwhile.

Optional: add a Space secret `HIBP_API_KEY` to switch the Footprint Scanner from
demo data to live HaveIBeenPwned lookups. Nothing else changes.

## Retraining the phishing model on your own dataset

Replace `data/phishing_dataset.csv` (two columns: `text,label`, label 1 =
phishing), then either:

```bash
# CLI: train and save to model_artifacts/phishing_distilbert/
python -m model.phishing_classifier            # full 2-epoch run
python -m model.phishing_classifier --limit 60 # quick smoke-train
```

…or simply delete the `model_artifacts/` folder and start the app: it retrains
itself in the background. The entry points to look at first are
`train()` in `model/phishing_classifier.py` (hyperparameters are the constants
at the top of that file) and the retraining notes in its module docstring.

## How the scores work (viva crib sheet)

- **Phishing risk** β€” ML mode blends `0.65 Γ— P(phishing from DistilBERT)` with
  `0.35 Γ— URL-heuristic score` when a link is present; rule mode blends
  keyword and URL scores 60/40. In ML mode the rule score is a guardrail: if
  the transparent heuristics are more alarmed than the model (a blind spot
  from the tiny dataset), the higher score wins. Every added point is listed
  in the UI.
- **Footprint exposure** β€” +16 per breach containing password data, +8 per
  data-only breach, +6 extra for breaches newer than ~3 years, capped at 100.
- **Behavioral risk** β€” `0.5 Γ— peak anomaly severity + 0.25 Γ— anomaly density +
  0.25 Γ— recency`; the detector is fully unsupervised but the CSV carries a
  `known_anomaly` column so the UI can show precision/recall against the
  planted truth (currently 6 of 7 caught).
- **Sage Score** β€” `0.40 Γ— phishing + 0.35 Γ— footprint + 0.25 Γ— behavior`,
  renormalized over whichever modules have run.

## Regenerating the demo data

```bash
python data/generate_login_data.py   # deterministic (seed 42)
```

## Deployment note

The primary target is Hugging Face Spaces (Gradio SDK), where this repo runs
with zero changes. A Vercel deployment would need a serverless-friendly
rewrite (Gradio on Node/Vercel is not supported; you would front the same
Python modules with a FastAPI + static UI) β€” out of scope for the hackathon,
but the `model/` and `utils/` packages are UI-agnostic and would carry over
unchanged.