<?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: XenoVenom</title>
    <description>The latest articles on DEV Community by XenoVenom (@xenovenom).</description>
    <link>https://dev.to/xenovenom</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%2F4097981%2F75b1ad3a-8960-413d-81d6-885da1a6bfb2.png</url>
      <title>DEV Community: XenoVenom</title>
      <link>https://dev.to/xenovenom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xenovenom"/>
    <language>en</language>
    <item>
      <title>How I Built a Zero-Database Address Poisoning Detector for Crypto Wallets</title>
      <dc:creator>XenoVenom</dc:creator>
      <pubDate>Tue, 27 Oct 2026 20:24:40 +0000</pubDate>
      <link>https://dev.to/xenovenom/how-i-built-a-zero-database-address-poisoning-detector-for-crypto-wallets-g0k</link>
      <guid>https://dev.to/xenovenom/how-i-built-a-zero-database-address-poisoning-detector-for-crypto-wallets-g0k</guid>
      <description>&lt;p&gt;&lt;em&gt;Detecting the silent scam that tricks users into sending funds to the wrong address — without storing any data.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Silent Killer of Crypto
&lt;/h2&gt;

&lt;p&gt;Address Poisoning is one of the most psychologically deceptive scams in Web3. It doesn't exploit smart contracts. It doesn't use malicious code. It exploits human habit.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You send 100 USDC to your friend at &lt;code&gt;0x1234...5678&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A scammer bot monitors the mempool and sees this transaction&lt;/li&gt;
&lt;li&gt;The scammer sends a 0-value transaction FROM an address that looks almost identical: &lt;code&gt;0x1234...5679&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Both transactions now appear in your MetaMask activity history&lt;/li&gt;
&lt;li&gt;Next time you want to send funds to your friend, you copy the address from your history&lt;/li&gt;
&lt;li&gt;You accidentally copy the scammer's address (because it looks 99% identical)&lt;/li&gt;
&lt;li&gt;You send your funds to the scammer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The scary part? No security tool catches this. The transaction is technically valid. The address is real. The wallet sends it. The funds are gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Traditional Tools Miss It
&lt;/h2&gt;

&lt;p&gt;Most crypto security extensions rely on blacklists — databases of known scam addresses. But address poisoning doesn't use "known scam addresses." It uses freshly generated wallets that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have no transaction history&lt;/li&gt;
&lt;li&gt;Aren't on any blacklist&lt;/li&gt;
&lt;li&gt;Look identical to legitimate addresses&lt;/li&gt;
&lt;li&gt;Change with every attack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A blacklist-based tool sees the transaction and says: &lt;em&gt;"This address isn't on our bad list. Looks safe!"&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;But it's not safe. It's a trap.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution: Local History + Heuristic Matching
&lt;/h2&gt;

&lt;p&gt;I realized the answer wasn't a better database — it was a better pattern.&lt;br&gt;
Instead of checking if an address is "known bad," we check if it looks suspiciously similar to one the user has interacted with before.&lt;/p&gt;

&lt;p&gt;Here's the architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Track&lt;/strong&gt; every address the user successfully interacts with (stored locally)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare&lt;/strong&gt; new transaction targets against this local history&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detect&lt;/strong&gt; if a new address shares the first 6 and last 4 characters with a known address&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block&lt;/strong&gt; the transaction with a visual warning&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No database. No API calls. No tracking. 100% local.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Technical Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1: The History Bridge&lt;/strong&gt;&lt;br&gt;
Because the core interception engine runs in the browser's &lt;code&gt;MAIN&lt;/code&gt; world (to hook into &lt;code&gt;window.ethereum&lt;/code&gt;), it can't access Chrome's storage API directly. So I created a bridge — a content script that listens for messages from the engine and handles storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// contents/history-bridge.ts
window.addEventListener("message", async (event) =&amp;gt; {
  // Check if an address is potentially poisoned
  if (event.data.type === "SAFESIGN_CHECK_POISON") {
    const checkAddress = event.data.payload.toLowerCase()

    // Fetch previously interacted addresses from local storage
    const result = await chrome.storage.local.get("safesign_history")
    const history: string[] = result.safesign_history || []

    let isPoison = false
    let matchedSafeAddress = ""

    for (const safeAddr of history) {
      if (safeAddr === checkAddress) {
        // Exact match = definitely safe
        isPoison = false
        break
      }

      // Heuristic: Check first 6 and last 4 characters
      if (safeAddr.length &amp;gt;= 10 &amp;amp;&amp;amp; checkAddress.length &amp;gt;= 10) {
        const safeStart = safeAddr.slice(0, 8) // "0x" + 6 chars
        const safeEnd = safeAddr.slice(-4)
        const checkStart = checkAddress.slice(0, 8)
        const checkEnd = checkAddress.slice(-4)

        if (safeStart === checkStart &amp;amp;&amp;amp; safeEnd === checkEnd) {
          // Similar but NOT exact = poison!
          isPoison = true
          matchedSafeAddress = safeAddr
          break
        }
      }
    }

    // Send result back to the engine
    window.postMessage({ 
      type: "SAFESIGN_POISON_RESULT", 
      payload: { isPoison, matchedSafeAddress, checkAddress } 
    }, "*")
  }

  // Add safe addresses to history after successful transactions
  if (event.data.type === "SAFESIGN_ADD_HISTORY") {
    const newAddress = event.data.payload.toLowerCase()
    const result = await chrome.storage.local.get("safesign_history")
    const history: string[] = result.safesign_history || []
    if (!history.includes(newAddress)) {
      history.push(newAddress)
      // Cap at 100 addresses to save space
      if (history.length &amp;gt; 100) history.shift()
      await chrome.storage.local.set({ safesign_history: history })
    }
  }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: The Detection Engine&lt;/strong&gt;&lt;br&gt;
In the main interception engine, before any transaction passes through to wallet, we ask the bridge to check the destination address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// contents/ethereum-listener.ts
if (args.method === "eth_sendTransaction") {
  const toAddress = txParams?.to?.toLowerCase()
  const fromAddress = txParams?.from?.toLowerCase()

  // Address Poisoning Check
  if (toAddress &amp;amp;&amp;amp; fromAddress) {
    const poisonCheck = await checkAddressPoisoning(toAddress)

    if (poisonCheck.isPoison) {
      // BLOCK: Show the Red Warning UI
      window.postMessage({ 
        type: "SAFESIGN_ALERT", 
        payload: { 
          dangerType: "POISONED_ADDRESS", 
          scamAddress: toAddress,
          rawData: `Similar to: ${poisonCheck.matchedSafeAddress}` 
        } 
      }, "*")
      throw new Error("SafeSign: Blocked Address Poisoning")
    }
  }

  // ... other security checks (blacklist, approvals, permits, etc.)

  // If all checks pass, add to history
  if (toAddress) {
    window.postMessage({ 
      type: "SAFESIGN_ADD_HISTORY", 
      payload: toAddress 
    }, "*")
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;checkAddressPoisoning&lt;/code&gt; helper uses a Promise-based message pattern to communicate with the bridge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const checkAddressPoisoning = (address: string) =&amp;gt; {
  return new Promise&amp;lt;{ isPoison: boolean, matchedSafeAddress: string }&amp;gt;((resolve) =&amp;gt; {
    const handleMessage = (event: MessageEvent) =&amp;gt; {
      if (event.data.type === "SAFESIGN_POISON_RESULT") {
        window.removeEventListener("message", handleMessage)
        resolve(event.data.payload)
      }
    }
    window.addEventListener("message", handleMessage)
    window.postMessage({ type: "SAFESIGN_CHECK_POISON", payload: address }, "*")
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Heuristic: Why 6 and 4?
&lt;/h2&gt;

&lt;p&gt;You might wonder: &lt;em&gt;why check the first 6 and last 4 characters?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ethereum addresses look like this: 0x + 40 hex characters.&lt;br&gt;
Scammers typically create vanity addresses that match:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First 4-6 characters&lt;/strong&gt; (what users visually scan)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Last 4 characters&lt;/strong&gt; (what users visually scan)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By checking 6 + 4, we catch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ The most common poisoning pattern&lt;/li&gt;
&lt;li&gt;✅ False positives are rare (1 in 4 billion chance of accidental match)&lt;/li&gt;
&lt;li&gt;✅ It's fast (simple string comparison)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Could we check more characters? Yes, but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More characters = more false negatives (scammers might only match 4+4)&lt;/li&gt;
&lt;li&gt;The 6+4 heuristic is the sweet spot between safety and accuracy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Privacy Architecture
&lt;/h2&gt;

&lt;p&gt;This was the most important design decision: &lt;strong&gt;zero data leaves the browser&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%2Fs080pjp9rwlk1l47ro2s.jpg" 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%2Fs080pjp9rwlk1l47ro2s.jpg" alt="No data exits this boundary" width="800" height="447"&gt;&lt;/a&gt;                &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ No backend server&lt;/li&gt;
&lt;li&gt;✅ No API calls&lt;/li&gt;
&lt;li&gt;✅ No analytics&lt;/li&gt;
&lt;li&gt;✅ No tracking&lt;/li&gt;
&lt;li&gt;✅ History capped at 100 addresses (~4.2 KB)&lt;/li&gt;
&lt;li&gt;✅ Stored in &lt;code&gt;chrome.storage.local&lt;/code&gt; (user's hard drive, not cloud)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The UX Decision: Why a Red Warning?
&lt;/h2&gt;

&lt;p&gt;When the detector triggers, SafeSign doesn't just silently block the transaction. It shows the Time-Travel UI with a specific message:&lt;br&gt;
&lt;strong&gt;"ADDRESS POISONING DETECTED"&lt;/strong&gt;&lt;br&gt;
This address looks almost identical to one you have used before, but it is a fake. Sending funds here will lose them forever.&lt;/p&gt;

&lt;p&gt;Why not a passive notification? Because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Users need to understand WHY&lt;/strong&gt; — otherwise they'll just retry with the same poisoned address&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual storytelling beats technical jargon&lt;/strong&gt; — "looks almost identical" is something anyone understands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Red UI creates a moment of pause&lt;/strong&gt; — users stop and think before acting&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What This Catches (And What It Doesn't)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;✅ Catches:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classic address poisoning (similar start + end)&lt;/li&gt;
&lt;li&gt;Vanity address spoofing&lt;/li&gt;
&lt;li&gt;Zero-value token transfers that pollute transaction history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❌ Doesn't Catch (Yet):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Addresses that only match 4+3 characters (too aggressive to block)&lt;/li&gt;
&lt;li&gt;Addresses with no prior history to compare against&lt;/li&gt;
&lt;li&gt;Cross-chain poisoning (Solana, etc.) — coming in v2.0&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;Address Poisoning is just one of the scams SafeSign blocks. But it represents something bigger: the philosophy of proactive, local-first security.&lt;br&gt;
Instead of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Waiting for someone to report a scam address&lt;/li&gt;
&lt;li&gt;❌ Maintaining a massive database&lt;/li&gt;
&lt;li&gt;❌ Sending user data to a server for analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Analyze patterns locally&lt;/li&gt;
&lt;li&gt;✅ Protect privacy by design&lt;/li&gt;
&lt;li&gt;✅ Catch zero-day scams that no database knows about&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the future of crypto security — not bigger databases, but smarter heuristics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;SafeSign is 100% free and open-source. If you want to protect yourself from address poisoning (and 6 other scam types), install it today.&lt;/p&gt;

&lt;p&gt;🔗 Chrome Web Store: &lt;a href="https://chromewebstore.google.com/detail/safesign-visualizer/fhnpgdlohkehmlgbjlmdoljbiojchfpb?authuser=0&amp;amp;hl=en-GB" rel="noopener noreferrer"&gt;SafeSign Visualizer&lt;/a&gt;&lt;br&gt;
💻 GitHub: &lt;a href="https://github.com/XenoVenom/safesign-visualizer" rel="noopener noreferrer"&gt;XenoVenom/safesign-visualizer&lt;/a&gt;&lt;br&gt;
🌐 Landing Page: &lt;a href="//safesignvisualizer.vercel.app"&gt;https://safesignvisualizer.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is Devlog #2 in a series about building SafeSign. In the next devlog, I'll break down how I intercept gasless EIP-2612 Permit signatures before wallet opens.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>javascript</category>
      <category>security</category>
      <category>cryptocurrency</category>
    </item>
    <item>
      <title>Why I Built SafeSign: The Panic UI Problem in Crypto Security</title>
      <dc:creator>XenoVenom</dc:creator>
      <pubDate>Thu, 22 Oct 2026 16:53:04 +0000</pubDate>
      <link>https://dev.to/xenovenom/why-i-built-safesign-the-panic-ui-problem-in-crypto-security-4dae</link>
      <guid>https://dev.to/xenovenom/why-i-built-safesign-the-panic-ui-problem-in-crypto-security-4dae</guid>
      <description>&lt;p&gt;&lt;em&gt;How watching friends get scammed led me to rethink crypto security from the ground up.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;If you spend enough time in Web3, you eventually see a friend get their wallet drained. It's devastating. One minute they're excited about a new DeFi opportunity, the next they're staring at a $0 balance and a transaction they don't remember authorizing.&lt;/p&gt;

&lt;p&gt;I've been there. Multiple times. Watching friends lose money to scams I could see coming—but couldn't explain to them in time.&lt;/p&gt;

&lt;p&gt;The most frustrating part wasn't the loss itself. It was the UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Flaw: Hex Codes Cause Alert Fatigue
&lt;/h2&gt;

&lt;p&gt;When a user encounters a malicious smart contract, most existing security tools show them something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️ MALICIOUS TRANSACTION DETECTED
Risk: HIGH
Function: 0x095ea7b3
Data: 0x095ea7b3000000000000000000000000deadbeef...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To a developer, this means: &lt;em&gt;"Unlimited approval to a suspicious address."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To a normal user, this means: &lt;em&gt;"I have no idea what this says. I'll just click Ignore."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And that's exactly what happens. Users experience &lt;strong&gt;alert fatigue&lt;/strong&gt;. They see scary-looking warnings they don't understand, and eventually they start ignoring them entirely. Or worse—they disable the security tool altogether because it "keeps interrupting them."&lt;br&gt;
This is the dirty secret of crypto security tools: &lt;strong&gt;they're built by security engineers, for security engineers&lt;/strong&gt;.&lt;br&gt;
The mass market—the regular people these tools claim to protect—can't use them effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "False Sense of Security" Problem
&lt;/h2&gt;

&lt;p&gt;There's a second, deeper flaw: &lt;strong&gt;blacklist dependency&lt;/strong&gt;.&lt;br&gt;
Most existing tools check transactions against a database of known bad addresses. If the address isn't on the list, the tool says "Safe."&lt;br&gt;
But scammers create new addresses every single minute. A brand-new scammer address won't be on any blacklist yet. The tool says "Safe"—and the user gets drained anyway.&lt;br&gt;
This creates a &lt;strong&gt;false sense of security&lt;/strong&gt;. Users trust the tool, the tool gives them a green light, and they lose everything.&lt;br&gt;
The system is &lt;strong&gt;reactive&lt;/strong&gt;, not &lt;strong&gt;proactive&lt;/strong&gt;. It waits for someone to lose money, then adds the address to a list. That's not protection—that's a obituary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Visual Storytelling
&lt;/h2&gt;

&lt;p&gt;I realized the answer wasn't a better database—it was a &lt;strong&gt;better language&lt;/strong&gt;.&lt;br&gt;
Instead of showing users hex codes and function signatures, what if we showed them the &lt;strong&gt;consequence&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;code&gt;Error: 0x095ea7b3...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Show them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Now:&lt;/strong&gt; You click Sign.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;+2 Seconds:&lt;/strong&gt; Site gets Unlimited Access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;+10 Seconds:&lt;/strong&gt; Wallet Drained. Balance: $0.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the "Time-Travel UI" concept. It doesn't ask users to understand bytecode. It shows them &lt;strong&gt;what happens next&lt;/strong&gt;.&lt;br&gt;
When a user sees a visual timeline of their wallet being drained, they don't need to understand &lt;code&gt;setApprovalForAll&lt;/code&gt; or &lt;code&gt;approve(spender, MAX_UINT)&lt;/code&gt;. They understand "drained." They understand "$0." They understand "don't click."&lt;br&gt;
&lt;strong&gt;Visual storytelling beats technical jargon. Every time.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Philosophy: Security as a Public Good
&lt;/h2&gt;

&lt;p&gt;As I built SafeSign, I made three core decisions that shape everything:&lt;br&gt;
&lt;strong&gt;1. Proactive, Not Reactive&lt;/strong&gt;&lt;br&gt;
SafeSign doesn't just check blacklists. It analyzes the logic of the transaction. If a contract asks for unlimited approval, SafeSign blocks it—even if the address is brand new and not on any list. It catches zero-day scams by understanding what the code does, not just who submitted it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Privacy-First, Always&lt;/strong&gt;&lt;br&gt;
No data collection. No tracking. No backend. Every analysis happens locally in the browser. Your wallet history, your transaction data, your browsing habits—none of it leaves your machine. Security tools shouldn't require you to surrender your privacy to be protected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Open-Source, Transparent&lt;/strong&gt;&lt;br&gt;
The entire codebase is on GitHub. Anyone can read every line. Anyone can verify there's no malicious behavior. Anyone can fork it, improve it, or audit it. In crypto, the rule is "don't trust, verify." I take that literally.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SafeSign Actually Does
&lt;/h2&gt;

&lt;p&gt;Since launching, SafeSign has grown into a comprehensive security layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unlimited Approval Blocks&lt;/strong&gt; (ERC-20 token drains)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NFT Collection Drain Blocks&lt;/strong&gt; (setApprovalForAll)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gasless Permit Drain Blocks&lt;/strong&gt; (EIP-2612 fake login scams)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address Poisoning Detection&lt;/strong&gt; (local, zero-database)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proactive Anti-Phishing&lt;/strong&gt; (known scam sites blocked entirely)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SIWE Domain Spoof Detection&lt;/strong&gt; (catches fake "Sign-In With Ethereum")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-Pause on Localhost&lt;/strong&gt; (developer-friendly)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual Time-Travel UI&lt;/strong&gt; (the core differentiator)
All free. All open-source. All local.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Mission
&lt;/h2&gt;

&lt;p&gt;If you want to protect your wallet (or just want to see the Time-Travel UI in action), SafeSign is free on the Chrome Web Store.&lt;/p&gt;

&lt;p&gt;The code is on GitHub. Read it. Fork it. Improve it.&lt;/p&gt;

&lt;p&gt;Security should be a public good.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Links:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://chromewebstore.google.com/detail/safesign-visualizer/fhnpgdlohkehmlgbjlmdoljbiojchfpb?authuser=0&amp;amp;hl=en-GB" rel="noopener noreferrer"&gt;Chrome Web Store&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/XenoVenom/safesign-visualizer" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;br&gt;
&lt;a href="https://x.com/Xen0Ven0m" rel="noopener noreferrer"&gt;Twitter/X&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is the first in a series of devlogs about building SafeSign. Next time, I'll break down the technical architecture of how I intercept &lt;code&gt;window.ethereum&lt;/code&gt; requests before wallet opens.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>security</category>
      <category>cryptocurrency</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How I built a Chrome Extension to intercept Crypto Wallet Drains (EIP-2612 &amp; ERC-20)</title>
      <dc:creator>XenoVenom</dc:creator>
      <pubDate>Mon, 31 Aug 2026 19:03:51 +0000</pubDate>
      <link>https://dev.to/xenovenom/how-i-built-a-chrome-extension-to-intercept-crypto-wallet-drains-eip-2612-erc-20-23ed</link>
      <guid>https://dev.to/xenovenom/how-i-built-a-chrome-extension-to-intercept-crypto-wallet-drains-eip-2612-erc-20-23ed</guid>
      <description>&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%2F2k3wkzku3a5t3st7xecx.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%2F2k3wkzku3a5t3st7xecx.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
If you spend enough time in Web3, you eventually see a friend get their wallet drained. The most frustrating part isn't just the loss of funds; it's the UI.&lt;/p&gt;

&lt;p&gt;When a user encounters a malicious smart contract, standard security tools often throw hex codes at them:&lt;/p&gt;

&lt;p&gt;⚠️ Error: 0x095ea7b3...&lt;/p&gt;

&lt;p&gt;Normal users panic, don't understand the alert, and click "Ignore" anyway. Or worse, they get "alert fatigue" and turn the tool off completely.&lt;/p&gt;

&lt;p&gt;I wanted to solve this "False Sense of Security" problem. So, I built SafeSign Visualizer—an open-source Chrome extension that intercepts malicious transactions before MetaMask opens, and translates them into a "Visual Time-Travel UI" that anyone can understand.&lt;/p&gt;

&lt;p&gt;In this post, I'll walk through the core architecture of how to intercept and decode Web3 scams using Plasmo and React.&lt;/p&gt;

&lt;p&gt;🧠 The Architecture: The "Man-in-the-Middle" Shield&lt;br&gt;
Chrome Extensions live in an "Isolated World." They cannot see the window.ethereum object that MetaMask injects into a webpage.&lt;/p&gt;

&lt;p&gt;To intercept a transaction, we must inject a script into the MAIN world of the page before MetaMask loads, and overwrite the window.ethereum.request function with a Proxy.&lt;/p&gt;

&lt;p&gt;Using Plasmo, this is incredibly clean. We create a content script that runs at document_start:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;import type { PlasmoCSConfig } from "plasmo"export const config: PlasmoCSConfig = {  matches: [""],  run_at: "document_start",  world: "MAIN" // This is the magic key}const intercept = () =&amp;gt; {  if (window.ethereum) {    const originalRequest = window.ethereum.request        // Overwrite the request function    window.ethereum.request = async (args) =&amp;gt; {      // 1. Analyze the transaction      // 2. If bad -&amp;gt; throw error (stops MetaMask)      // 3. If good -&amp;gt; return originalRequest(...)    }  } else {    setTimeout(intercept, 50) // Wait for wallet to load  }}intercept()&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🛡️ Decoding the Scams (Heuristics)&lt;br&gt;
Once we intercept the request, we need to analyze the args.params[0].data to see what the smart contract is actually trying to do.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Unlimited Token Approval (ERC-20)
The most common drain. A site asks you to swap, but the hidden code calls the approve function (0x095ea7b3) with the maximum possible integer (ffffffff...).
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eth_sendTransaction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x095ea7b3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Extract the amount (last 32 bytes)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amountHex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;74&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxUint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amountHex&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;maxUint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;// BLOCK! Scammer is asking for infinite access.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;The "Invisible" Gasless Drain (EIP-2612)
This is the most dangerous scam right now. Scammers use a fake "Sign-In With Ethereum" button. It costs no gas, so users think it's harmless. But hidden in the eth_signTypedData_v4 payload is a Permit signature.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By signing it, the user gives the scammer a legal off-chain permission slip to drain their USDT later.&lt;/p&gt;

&lt;p&gt;To stop this, we parse the JSON payload of the signature request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eth_signTypedData_v4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPermit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;typedData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;primaryType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Permit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasPermitFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;typedData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;spender&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;typedData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isPermit&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;hasPermitFields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="c1"&gt;// BLOCK! This is a gasless permit drain.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎨 Visual Storytelling (The UI)&lt;br&gt;
When a scam is detected, we throw an error to stop MetaMask from opening, and we send a window.postMessage to our React Content Script UI to mount a full-screen overlay.&lt;/p&gt;

&lt;p&gt;Instead of technical jargon, we show a timeline of the consequence:&lt;/p&gt;

&lt;p&gt;Now: You click sign.&lt;br&gt;
+2 Seconds: Site gets Unlimited Access.&lt;br&gt;
+10 Seconds: Wallet Drained.&lt;br&gt;
This "Visual Storytelling" approach ensures that non-technical users actually understand why they shouldn't click sign, rather than just ignoring a red warning box.&lt;/p&gt;

&lt;p&gt;🚀 Open Source&lt;br&gt;
I built SafeSign to be 100% free, open-source, and privacy-first. There is no backend, no tracking, and no data collection. All analysis happens locally in the browser.&lt;/p&gt;

&lt;p&gt;If you want to look at the exact code, borrow the interception logic for your own dApp, or install it to protect your own wallet, you can find it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/XenoVenom/safesign-visualizer" rel="noopener noreferrer"&gt;💻 GitHub Repository&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tinyurl.com/4t6w7p48" rel="noopener noreferrer"&gt;🌐 Chrome Web Store&lt;/a&gt;&lt;br&gt;
I'd love to hear your feedback on the architecture or any ideas you have for improving the heuristics!&lt;/p&gt;

</description>
      <category>web3</category>
      <category>javascript</category>
      <category>react</category>
      <category>security</category>
    </item>
  </channel>
</rss>
