{"slug": "my-friend-almost-got-phished-so-i-built-him-a-local-ai-bodyguard-in-one-weekend", "title": "My friend almost got phished — so I built him a local AI bodyguard in one weekend", "summary": "A developer built PhishGuard, an offline phishing checker that combines a deterministic heuristic engine (~15 signals) with a local LLM second opinion via Ollama and the open-weight gemma3:2b model, returning SAFE, SUSPICIOUS or PHISHING verdicts with a readable point-by-point score. The tool extracts links from pasted URLs or full messages, catches look-alike domains and display-name/sender mismatches, and makes zero network calls so suspicious content never leaves the user's machine. When Ollama is unavailable it falls back to the rules engine alone.", "body_md": "📅 DEV Weekend Challenge: **Build for a Friend** · Hacktoberfest 2026\n\n🔗 Repo: [https://github.com/shri7-lab/phishguard](https://github.com/shri7-lab/phishguard)\n\n🌐 Live demo: [https://phishguard-oi4y.onrender.com](https://phishguard-oi4y.onrender.com)\n\n`gemma3:2b` runs as the local AI second-opinion through Ollama\nFriday night, 11:47 PM. A friend forwards this on WhatsApp:\n\n\"URGENT: Your IES College fee payment FAILED. Registration will be cancelled in 24 hours. Re-verify now: `bit.ly/fee-refund-2026`\"\n\nHe was about to tap it. He's not careless with tech, he was just tired. And honestly that message would fool half our college group — it *looks* official.\n\nI told him to send it to me first. Then I opened a couple of those \"is this link safe?\" websites... and stopped midway. Wait — I'm about to paste a *suspicious* link into some random cloud service? Now their server has the link, my query, everything. That's like a cop announcing his own address during a raid. Anyway.\n\nClosed those tabs, told him: give me the weekend.\n\n**PhishGuard — a phishing checker that doesn't phone home.**\n\nPaste a URL, or dump the whole message — WhatsApp forward, SMS, Discord DM, whatever. You get one of three verdicts (`✅ SAFE` / `🟠 SUSPICIOUS` / `🔴 PHISHING`) plus the maths behind it:\n\n```\nVerdict : 🔴 PHISHING  (score 75/100)\n  link: http://192.168.0.1/bank-login-verify?otp=update-account\n    +35p  raw IP address instead of a real domain\n    +10p  plain HTTP — no encryption\n    +30p  scare/urgency keywords: account, bank, login, otp, update, verify\n```\n\nNo black box. Every point maps to a reason an actual human can read.\n\nScams in 2026 aren't just dirty URLs anymore though, so the scanner handles those too — and all of this runs offline, zero network calls:\n\n`paypal-secure.tk`, `g00gle-login.com` (digits get normalized, `g00gle` → `google`, and Cyrillic look-alikes like `gооgle` get caught too)`http://...`\n`PayPal Security <secure@paypa1-support.xyz>`, where the display name and the actual domain disagree\n\n```\n  message:\n    +30p  hidden URL inside an encoded blob → http://evil.test/login\n    +25p  display name says 'PayPal Security' but sender is paypa1-support.xyz\n```\n\nI didn't want to pick one. Blocklists alone miss brand-new scams. LLMs alone hallucinate, and they want your data sitting on someone else's computer. So it runs both:\n\n```\n message ──► Link extractor ──► Heuristic engine (deterministic, ~15 signals)\n                    │\n                    └──────────► Local LLM second opinion (Ollama + gemma3:2b, offline)\n                                        │\n                                  final verdict (worst of both wins)\n```\n\nThe AI part runs on my laptop through [Ollama](https://ollama.com) using an open-weight model (`gemma3:2b`). No API key, no telemetry, nothing leaves the machine.\n\nBest part — they disagree sometimes, and that's useful. A forward that reads fine but hides a `.top` shortener: rules catch it. A message with zero suspicious keywords that just *feels* wrong (\"your SIM will be deactivated, call 198 now\"): rules give it 0/100, the model straight up says PHISHING. That exact example is in \"Try it yourself\" below, try it yourself.\n\nThe AI call, the whole thing, is honestly just this:\n\n``` python\ndef ask_ollama(text):\n    body = json.dumps({\"model\": \"gemma3:2b\", \"prompt\": prompt, \"stream\": False}).encode()\n    req = urllib.request.Request(OLLAMA + \"/api/generate\", data=body, ...)\n    with urllib.request.urlopen(req, timeout=45) as resp:\n        return json.loads(resp.read().decode())[\"response\"]\n```\n\nIf Ollama isn't running, it tells you and falls back to the rules. No pretending to be smarter than it is.\n\nThe whole product promise is *\"your data never leaves your machine.\"* That promise only exists because the model underneath is open and local. Swap it for a closed API — even a good one — and PhishGuard becomes the exact thing I was warning my friend about: paste your suspicious thing here and trust us.\n\nOpen also means readable. Those ~15 scoring rules live in one Python file. Someone can disagree with rule #7 tonight and send a PR tomorrow. Try doing that with a fraud score buried inside a banking app.\n\nAnd practically — my friend runs it with the Wi-Fi off. For a security tool, that kind of matters.\n\nNo install needed (heuristic engine, hosted on Render):\n\n👉 [https://phishguard-oi4y.onrender.com](https://phishguard-oi4y.onrender.com)\n\nWith the AI — about 30 seconds of setup. This is the part the hosted demo deliberately skips, because your suspicious link shouldn't be travelling anywhere:\n\n```\ngit clone https://github.com/shri7-lab/phishguard.git && cd phishguard\nbrew install ollama && ollama pull gemma3:2b    # Linux: curl -fsSL https://ollama.com/install.sh | sh\npython3 phishguard.py check \"Your SIM will be deactivated today. Call 198 to re-validate\"\nVerdict : 🔴 PHISHING  (score 0/100)\nnote    : no link/payload found — local AI weighed in on the text\n  AI: PHISHING — SIM deactivation threat and urgency to call a number\n  are not genuine, potentially suspicious activity.\n```\n\nThe rules scored that message 0/100 — SAFE. The open-weight model caught it. That one example is basically the entire architecture.\n\nTests are there too: `python3 -m unittest discover -s tests` → `Ran 12 tests ... OK`. Yeah, unit tests in a weekend project — I changed a score value at 1 AM, broke two verdicts without noticing, and then the suite earned its place permanently.\n\n`phishguard.py` is one file, Python standard library only. No pip install, no virtualenv drama, no node_modules. My friend — the same guy who almost clicked the link — ran exactly this much:\n\n```\ngit clone https://github.com/shri7-lab/phishguard.git\npython3 phishguard.py check \"bit.ly/fee-refund-2026\"\n```\n\nThere's a browser mode as well, for people who won't open a terminal:\n\n```\npython3 phishguard.py web   # localhost:8080\n```\n\nI handed it over to him on Sunday over a screen-share. He pasted that same `bit.ly/fee-refund-2026` forward into it, got `🟠 SUSPICIOUS — link shortener hides the real destination`, and said:\n\n\"Bhai, ab click karne se pehle yahi check karunga — screenshot wali baat samajh aa gayi.\"\n\nThat one line made the whole weekend worth it.\n\nSaturday morning: link extractor plus the scoring rules (full table is in the README). Saturday night turned into the Ollama integration — making the JSON reply behave took longer than the scoring engine did, I'm not joking. Sunday was the web UI, the README and this post, and testing on every scam message sitting in my WhatsApp archive (yes, I have a folder for them, yes, it's depressing).\n\nWhat surprised me: almost all the advice online is \"check the lock icon, check the spelling.\" Nobody does that at 11 PM. People just need a second pair of eyes that answers in 2 seconds.\n\nI'm 18, first year CSE, and I spend nights on Hack The Box instead of Instagram. If PhishGuard saves even one person from a \"fee refund\" scam, that beats any star count on GitHub.\n\nTry it, break it, send a PR. Happy Hacktoberfest 🎃\n\n`#hf26challenge` `#weekendchallenge` `#ai`", "url": "https://wpnews.pro/news/my-friend-almost-got-phished-so-i-built-him-a-local-ai-bodyguard-in-one-weekend", "canonical_source": "https://dev.to/shriyanshgupta145/my-friend-almost-got-phished-so-i-built-him-a-local-ai-bodyguard-in-one-weekend-5b43", "published_at": "2026-10-04 13:32:53+00:00", "updated_at": "2026-10-04 13:42:42.042405+00:00", "lang": "en", "topics": ["ai-tools", "large-language-models", "ai-products", "artificial-intelligence"], "entities": ["PhishGuard", "Ollama", "gemma3:2b", "GitHub", "WhatsApp", "PayPal"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/my-friend-almost-got-phished-so-i-built-him-a-local-ai-bodyguard-in-one-weekend", "markdown": "https://wpnews.pro/news/my-friend-almost-got-phished-so-i-built-him-a-local-ai-bodyguard-in-one-weekend.md", "text": "https://wpnews.pro/news/my-friend-almost-got-phished-so-i-built-him-a-local-ai-bodyguard-in-one-weekend.txt", "jsonld": "https://wpnews.pro/news/my-friend-almost-got-phished-so-i-built-him-a-local-ai-bodyguard-in-one-weekend.jsonld"}}