Inspiration

My family calls me when a text looks suspicious. "Your package is held at customs." "Your account has been suspended." Every time, the message has obvious tells — a domain that isn't quite the real one, a deadline invented to stop you thinking — but the tells are only obvious if you already know what to look for.

That's the gap. The tools that exist either assume a security background, or they return a bare "spam / not spam" label that teaches the person nothing and gives them no reason to trust it. Someone who's been told "this is suspicious" with no explanation still doesn't know whether to click, and still won't recognize the next one.

I wanted to build the thing I'd want my parents to have open on their phone: paste the message, get a straight answer, understand why, and know exactly what to do next.

What it does

PhishGuard AI analyzes any pasted email, SMS, DM, or link and returns an explained verdict in a few seconds.

  • A calibrated 0–100 risk score with a clear verdict — Low, Medium, High, or Critical
  • The exact signals that triggered it, grouped into Link signals and Language signals, each showing the specific text or domain that matched, ranked by severity
  • A plain-English explanation naming the likely scam type — phishing, tech support scam, prize scam, business email compromise
  • Concrete next steps tailored to the verdict: what not to click, what never to reply with, how to verify the sender independently, and what to do immediately if you already clicked
  • Defanged links — every URL found is displayed as hxxp://example[.]com so you can't accidentally click a live scam link while reading the analysis
  • Four one-click examples, including a legitimate email as a control, so anyone can confirm in ten seconds that it makes real judgments rather than flagging anything containing a URL

Nothing you paste is stored. Messages are analyzed in memory and never written to disk or logged.

How we built it

Two layers, deliberately separated.

Layer 1 — a deterministic rule engine. Hand-written TypeScript running 16+ checks with no AI involved:

Link analysis — registrable-domain extraction and brand-mismatch detection (a link claiming to be Chase whose actual domain is account-alerts.xyz), punycode/lookalike-character detection, raw IP addresses, the @-symbol redirect trick, URL shorteners, heavily-abused TLDs, subdomain burying, missing HTTPS, and obfuscation-length heuristics.

Language analysis — manufactured urgency, credential and payment requests, threats of loss or legal action, unearned prizes, generic greetings, and pressure to call a number or keep the matter secret.

Layer 2 — AI reasoning. Those signals, plus the original message, go to Claude via the Anthropic API under a strict JSON response contract. Claude returns the scam category, the plain-English explanation, and its own independent 0–100 estimate. The two scores are then blended.

Stack: Next.js 14 (App Router) with TypeScript, analysis running server-side so detection logic and prompts never reach the client; Tailwind CSS with an animated SVG risk gauge, skeleton loading states, aria-live result announcements, keyboard shortcuts, and prefers-reduced-motion support; deployed on Vercel.

Challenges we ran into

The scoring was quietly broken. My first version summed signal weights linearly. It looked fine — scam messages scored "high" — until I screenshotted several results side by side and realized almost everything was pinning at 100/100. Technically it flagged the right messages, but it was useless: a user couldn't distinguish a mildly suspicious email from a certain one, and a score that's always maxed is a score nobody believes. I replaced the linear sum with a saturating exponential curve, so stacking many weak signals never reaches the same certainty as one decisive signal like a brand-domain mismatch. The same four test messages now score 78, 73, 80, and 0 — a spread that actually carries information.

Resisting the urge to make the model do everything. Handing the raw message to an LLM and asking "is this a scam?" is one API call and demos beautifully. It's also unauditable, slower, and fails completely when the API is down or rate-limited. Splitting deterministic detection from AI explanation meant more work, but the rule engine is inspectable, runs instantly, and returns a complete result on its own — so the tool still protects someone when the AI layer is unavailable. It also meant I could show the user which signals fired, which is the entire basis for trusting the verdict.

Writing for someone who's scared, not someone who's curious. Early copy said things like "punycode encoding detected." Accurate and useless. Every signal label got rewritten for a person who doesn't know what a TLD is — "Domain uses lookalike characters to imitate a real site."

Accomplishments that we're proud of

A tool that's actually usable rather than a prototype that only works on demo inputs. It's simple enough for a non-technical person under stress, transparent enough for a security-minded one to audit, and it degrades gracefully instead of breaking when the AI layer fails.

The details I'm most pleased with are the small ones: defanging every displayed link so the analysis screen can't itself become the attack, and shipping a legitimate email as a built-in example — showing what the tool doesn't flag is the fastest way to earn trust in a detector.

What we learned

How much reliable scam detection is achievable with cheap, fast, fully explainable heuristics before an LLM enters the picture at all. The model's real contribution here turned out not to be classification — the rule engine is already good at that — but translation: turning a list of technical signals into reasoning a worried, non-technical person can act on at the moment they need it.

I also learned to distrust a detector that agrees with me too easily. The linear-scoring bug survived because every test message I threw at it was obviously a scam, so "100/100" always looked right. It only surfaced when I tested what the distribution looked like, not whether individual answers were correct.

What's next for PhishGuard AI

  • A browser extension, so links are checked before the click rather than after
  • Live domain-age and certificate lookups to catch freshly registered scam infrastructure, which is the single strongest signal I'm not yet using
  • Multi-language support — SMS scams disproportionately target non-English speakers, and the language heuristics are currently English-only
  • A shareable result link, so someone can send an analysis to the family member who forwarded them the message
  • Bulk inbox scanning for people who act as the informal tech support for their whole family

Built With

Share this project:

Updates

Submission history