<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shriyansh Gupta</title>
    <description>The latest articles on DEV Community by Shriyansh Gupta (@shriyanshgupta145).</description>
    <link>https://dev.to/shriyanshgupta145</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160323%2F74b21dbd-11f4-4277-b4f3-8cb8f503295a.jpg</url>
      <title>DEV Community: Shriyansh Gupta</title>
      <link>https://dev.to/shriyanshgupta145</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shriyanshgupta145"/>
    <language>en</language>
    <item>
      <title>My friend almost got phished — so I built him a local AI bodyguard in one weekend</title>
      <dc:creator>Shriyansh Gupta</dc:creator>
      <pubDate>Sun, 04 Oct 2026 13:32:53 +0000</pubDate>
      <link>https://dev.to/shriyanshgupta145/my-friend-almost-got-phished-so-i-built-him-a-local-ai-bodyguard-in-one-weekend-5b43</link>
      <guid>https://dev.to/shriyanshgupta145/my-friend-almost-got-phished-so-i-built-him-a-local-ai-bodyguard-in-one-weekend-5b43</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;📅 DEV Weekend Challenge: &lt;strong&gt;Build for a Friend&lt;/strong&gt; · Hacktoberfest 2026&lt;br&gt;
🔗 Repo: &lt;a href="https://github.com/shri7-lab/phishguard" rel="noopener noreferrer"&gt;https://github.com/shri7-lab/phishguard&lt;/a&gt;&lt;br&gt;
🌐 Live demo: &lt;a href="https://phishguard-oi4y.onrender.com" rel="noopener noreferrer"&gt;https://phishguard-oi4y.onrender.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — &lt;code&gt;gemma3:2b&lt;/code&gt; runs as the local AI second-opinion through Ollama&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render&lt;/strong&gt; — the web demo is hosted on Render (link above)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Friday night, 11:47 PM. A friend forwards this on WhatsApp:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"URGENT: Your IES College fee payment FAILED. Registration will be cancelled in 24 hours. Re-verify now: &lt;code&gt;bit.ly/fee-refund-2026&lt;/code&gt;"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He 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 &lt;em&gt;looks&lt;/em&gt; official.&lt;/p&gt;

&lt;p&gt;I 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 &lt;em&gt;suspicious&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;Closed those tabs, told him: give me the weekend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PhishGuard — a phishing checker that doesn't phone home.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe6jk1kypea0vhe3emekh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe6jk1kypea0vhe3emekh.png" alt="PhishGuard CLI — phishing verdict with score breakdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it actually does
&lt;/h2&gt;

&lt;p&gt;Paste a URL, or dump the whole message — WhatsApp forward, SMS, Discord DM, whatever. You get one of three verdicts (&lt;code&gt;✅ SAFE&lt;/code&gt; / &lt;code&gt;🟠 SUSPICIOUS&lt;/code&gt; / &lt;code&gt;🔴 PHISHING&lt;/code&gt;) plus the maths behind it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Verdict : 🔴 PHISHING  (score 75/100)
  link: http://192.168.0.1/bank-login-verify?otp=update-account
    +35p  raw IP address instead of a real domain
    +10p  plain HTTP — no encryption
    +30p  scare/urgency keywords: account, bank, login, otp, update, verify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No black box. Every point maps to a reason an actual human can read.&lt;/p&gt;

&lt;p&gt;Scams in 2026 aren't just dirty URLs anymore though, so the scanner handles those too — and all of this runs offline, zero network calls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;brands being used by domains that don't own them — &lt;code&gt;paypal-secure.tk&lt;/code&gt;, &lt;code&gt;g00gle-login.com&lt;/code&gt; (digits get normalized, &lt;code&gt;g00gle&lt;/code&gt; → &lt;code&gt;google&lt;/code&gt;, and Cyrillic look-alikes like &lt;code&gt;gооgle&lt;/code&gt; get caught too)&lt;/li&gt;
&lt;li&gt;a base64 or hex blob sitting in the message that decodes to a hidden &lt;code&gt;http://...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;fake sender identities — &lt;code&gt;PayPal Security &amp;lt;secure@paypa1-support.xyz&amp;gt;&lt;/code&gt;, where the display name and the actual domain disagree
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  message:
    +30p  hidden URL inside an encoded blob → http://evil.test/login
    +25p  display name says 'PayPal Security' but sender is paypa1-support.xyz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rules + a local LLM, layered
&lt;/h2&gt;

&lt;p&gt;I 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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; message ──► Link extractor ──► Heuristic engine (deterministic, ~15 signals)
                    │
                    └──────────► Local LLM second opinion (Ollama + gemma3:2b, offline)
                                        │
                                  final verdict (worst of both wins)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI part runs on my laptop through &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; using an open-weight model (&lt;code&gt;gemma3:2b&lt;/code&gt;). No API key, no telemetry, nothing leaves the machine.&lt;/p&gt;

&lt;p&gt;Best part — they disagree sometimes, and that's useful. A forward that reads fine but hides a &lt;code&gt;.top&lt;/code&gt; shortener: rules catch it. A message with zero suspicious keywords that just &lt;em&gt;feels&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;The AI call, the whole thing, is honestly just this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ask_ollama&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemma3:2b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OLLAMA&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/generate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If Ollama isn't running, it tells you and falls back to the rules. No pretending to be smarter than it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open innovation matters (the prompt asked, so here's my honest answer)
&lt;/h2&gt;

&lt;p&gt;The whole product promise is &lt;em&gt;"your data never leaves your machine."&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;Open 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.&lt;/p&gt;

&lt;p&gt;And practically — my friend runs it with the Wi-Fi off. For a security tool, that kind of matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;No install needed (heuristic engine, hosted on Render):&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://phishguard-oi4y.onrender.com" rel="noopener noreferrer"&gt;https://phishguard-oi4y.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With 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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/shri7-lab/phishguard.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;phishguard
brew &lt;span class="nb"&gt;install &lt;/span&gt;ollama &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ollama pull gemma3:2b    &lt;span class="c"&gt;# Linux: curl -fsSL https://ollama.com/install.sh | sh&lt;/span&gt;
python3 phishguard.py check &lt;span class="s2"&gt;"Your SIM will be deactivated today. Call 198 to re-validate"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Verdict : 🔴 PHISHING  (score 0/100)
note    : no link/payload found — local AI weighed in on the text
  AI: PHISHING — SIM deactivation threat and urgency to call a number
  are not genuine, potentially suspicious activity.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rules scored that message 0/100 — SAFE. The open-weight model caught it. That one example is basically the entire architecture.&lt;/p&gt;

&lt;p&gt;Tests are there too: &lt;code&gt;python3 -m unittest discover -s tests&lt;/code&gt; → &lt;code&gt;Ran 12 tests ... OK&lt;/code&gt;. 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zero dependencies (this was non-negotiable)
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;phishguard.py&lt;/code&gt; 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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/shri7-lab/phishguard.git
python3 phishguard.py check &lt;span class="s2"&gt;"bit.ly/fee-refund-2026"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a browser mode as well, for people who won't open a terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 phishguard.py web   &lt;span class="c"&gt;# localhost:8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F353bxdj4lcslirwweznj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F353bxdj4lcslirwweznj.png" alt="PhishGuard browser demo — paste link, get an explained verdict"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I handed it over to him on Sunday over a screen-share. He pasted that same &lt;code&gt;bit.ly/fee-refund-2026&lt;/code&gt; forward into it, got &lt;code&gt;🟠 SUSPICIOUS — link shortener hides the real destination&lt;/code&gt;, and said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Bhai, ab click karne se pehle yahi check karunga — screenshot wali baat samajh aa gayi."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That one line made the whole weekend worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the weekend actually went
&lt;/h2&gt;

&lt;p&gt;Saturday 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).&lt;/p&gt;

&lt;p&gt;What 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things I'm leaving on the table (steal these)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;QR-code decoding for those "scan to pay" scam posters&lt;/li&gt;
&lt;li&gt;Indian UPI / vishing number patterns — we get these daily&lt;/li&gt;
&lt;li&gt;A browser extension wrapper&lt;/li&gt;
&lt;li&gt;A pre-commit hook so you can't push your own API keys by accident&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I'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.&lt;/p&gt;

&lt;p&gt;Try it, break it, send a PR. Happy Hacktoberfest 🎃&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#hf26challenge&lt;/code&gt; &lt;code&gt;#weekendchallenge&lt;/code&gt; &lt;code&gt;#ai&lt;/code&gt;&lt;/p&gt;

</description>
      <category>hf26challenge</category>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
