<?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: Yoel Frischoff</title>
    <description>The latest articles on DEV Community by Yoel Frischoff (@yoelf22).</description>
    <link>https://dev.to/yoelf22</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3827808%2F839487e1-0c97-49f6-9941-c6606cbc6fd9.jpg</url>
      <title>DEV Community: Yoel Frischoff</title>
      <link>https://dev.to/yoelf22</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yoelf22"/>
    <language>en</language>
    <item>
      <title>I Built a Gmail Spoof Detector That Catches Unicode Homoglyph Phishing</title>
      <dc:creator>Yoel Frischoff</dc:creator>
      <pubDate>Mon, 16 Mar 2026 17:32:04 +0000</pubDate>
      <link>https://dev.to/yoelf22/i-built-a-gmail-spoof-detector-that-catches-unicode-homoglyph-phishing-45j5</link>
      <guid>https://dev.to/yoelf22/i-built-a-gmail-spoof-detector-that-catches-unicode-homoglyph-phishing-45j5</guid>
      <description>&lt;p&gt;## The attack&lt;/p&gt;

&lt;p&gt;I got an email from "Wіх.соm" asking me to verify my account. Looked legit — until I checked the actual sender: &lt;code&gt;info@bistro-pub.de&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The trick? The display name used Cyrillic &lt;strong&gt;і&lt;/strong&gt; (U+0456) and &lt;strong&gt;о&lt;/strong&gt; (U+043E) instead of Latin &lt;strong&gt;i&lt;/strong&gt; and &lt;strong&gt;o&lt;/strong&gt;. They're visually identical in most&lt;br&gt;
  fonts. Gmail didn't flag it because the From address wasn't technically spoofed — only the display name was.&lt;/p&gt;

&lt;p&gt;This is called &lt;strong&gt;homoglyph spoofing&lt;/strong&gt;, and it works because Unicode includes hundreds of characters that look exactly like Latin letters:&lt;/p&gt;

&lt;p&gt;| Character | Looks like | Actually |&lt;br&gt;
  |-----------|-----------|----------|&lt;br&gt;
  | а (U+0430) | a | Cyrillic |&lt;br&gt;
  | с (U+0441) | c | Cyrillic |&lt;br&gt;
  | е (U+0435) | e | Cyrillic |&lt;br&gt;
  | о (U+043E) | o | Cyrillic |&lt;br&gt;
  | р (U+0440) | p | Cyrillic |&lt;br&gt;
  | і (U+0456) | i | Ukrainian Cyrillic |&lt;br&gt;
  | Ａ (U+FF21) | A | Fullwidth Latin |&lt;/p&gt;

&lt;p&gt;## The fix&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Unspoofer&lt;/strong&gt; — a Google Apps Script that runs inside your Gmail account and catches these automatically. No browser extension, no&lt;br&gt;
  third-party service.&lt;/p&gt;

&lt;p&gt;### How it works&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Normalize homoglyphs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A map of ~80 Cyrillic, Greek, and fullwidth characters gets applied to every sender display name:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
js
  const HOMOGLYPH_MAP = {
    '\u0430': 'a', // Cyrillic а
    '\u0441': 'c', // Cyrillic с
    '\u0435': 'e', // Cyrillic е
    '\u043E': 'o', // Cyrillic о
    '\u0456': 'i', // Ukrainian і
    // ... ~80 total mappings
  };

  function normalizeToAscii(str) {
    let result = '';
    for (let i = 0; i &amp;lt; str.length; i++) {
      result += HOMOGLYPH_MAP[str[i]] || str[i];
    }
    return result.toLowerCase();
  }

  So "Wіх.соm" becomes "wix.com".

  2. Match against known brands

  The normalized name is checked against ~50 brand domains (Google, PayPal, Apple, Amazon, banks, shipping companies, etc.). Both full domain matches
   (wix.com) and standalone brand name matches (paypal) are checked, with word-boundary logic to avoid false positives.

  3. Compare domains

  If the display name implies a brand, the script extracts the root domain from the actual sender email and compares:

  - "Wix.com" &amp;lt;noreply@mail.wix.com&amp;gt; — root domains match → legit
  - "Wіх.соm" &amp;lt;info@bistro-pub.de&amp;gt; — wix.com ≠ bistro-pub.de → spoof

  Root domain extraction handles compound TLDs like .co.il and .co.uk correctly.

  4. Flag it

  Spoofed messages get a SPOOF-ALERT Gmail label and a star. The label shows up as a folder in any mail client; the star shows as a flag in Apple
  Mail.

  Architecture

  The whole thing runs as a 15-minute time-driven trigger:

  Trigger (every 15 min)
    → Search: in:inbox newer_than:1d
    → For each message:
        → Check processed-ID cache (skip if seen)
        → Parse From header → display name + email
        → Normalize homoglyphs → check brand list
        → Compare implied domain vs actual domain
        → If mismatch: apply label + star
    → Flush cache to PropertiesService

  The processed-message cache uses a rolling window of 10,000 IDs stored as JSON in ScriptProperties, so messages aren't re-checked across runs. An
  execution time guard breaks the loop before hitting the 6-minute Apps Script limit.

  Try it

  Setup takes about 2 minutes:

  1. Create a new project at https://script.google.com
  2. Copy 5 .gs files from the repo
  3. Run testDetection() to verify (9 test cases)
  4. Run setup() to activate

  GitHub: [https://github.com/yoelf22/unspoofer
]
  Free, open source, MIT licensed. PRs welcome — especially for expanding the homoglyph map or brand list.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>cybersecurity</category>
      <category>infosec</category>
      <category>security</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
