Skip to main content
Your user pasted an address from their clipboard. It looked right—but it wasn’t. The first four characters matched. The last four matched. But in the middle, a scammer had swapped characters. $68 million in WBTC, gone in one transaction. This guide shows you how to protect your users from these attacks before they happen.

Why Wallets Need Security

Send Protection

Verify addresses before your users send funds to scammers

Transaction Preview

Show users what they’re signing before they sign it

Phishing Defense

Block malicious dApps before they drain wallets
Why wallet developers choose Webacy:
  • Address poisoning detection — The attack that stole $68M in one transaction
  • Transaction simulation — Show users exactly what will happen before signing
  • EIP-712 signature analysis — Catch permit phishing attacks
  • URL screening — Block known phishing sites in your dApp browser
  • Sub-500ms response times — Security without blocking the user experience

Prerequisites

Before implementing wallet security, ensure you have:
  • A Webacy API key (sign up here)
  • Basic familiarity with REST APIs or the Webacy SDK
  • Your wallet’s send flow and transaction signing identified for integration points

Send Flow Protection

The send flow is where users are most vulnerable. A simple address check can save them from losing everything.

Quick Profile Before Sending

Before showing the send confirmation, check the destination address.
curl -X GET "https://api.webacy.com/addresses/0xd9A1C3788D81257612E2581A6ea0aDa244853a91/quick-profile?chain=eth" \
  -H "x-api-key: YOUR_API_KEY"
Use the response to guide users:
Risk LevelAction
lowProceed normally
mediumShow caution banner
highRequire explicit confirmation
criticalBlock and explain why

Address Poisoning Detection

Address poisoning attacks are devastating because they exploit user trust. Scammers create addresses that look nearly identical to legitimate ones.
Real Case: In May 2024, a victim copied what they thought was their own address from transaction history. The attacker’s address matched the first and last characters perfectly. $68 million in WBTC, gone.
Can you spot the difference?
Address
✅ Legitimate0xd9A1b0B1e1aE382DbDc898Ea68012FfcB2853a91
❌ Attacker0xd9A1C3788D81257612E2581A6ea0aDa244853a91
Both start with 0xd9A1. Both end with 53a91. The scammer generated a vanity address specifically to match the victim’s transaction history.
curl -X GET "https://api.webacy.com/addresses/0xd9A1C3788D81257612E2581A6ea0aDa244853a91/poisoning?chain=eth" \
  -H "x-api-key: YOUR_API_KEY"
Integration tip: Run this check whenever a user pastes an address. The 300ms latency is invisible to users—but catching a poisoning attack is priceless.

Sanctions Screening

Prevent users from sending to sanctioned addresses and protect your platform from regulatory risk.
curl -X GET "https://api.webacy.com/addresses/sanctioned/0x098B716B8Aaf21512996dC57EB0615e2383E2f96?chain=eth" \
  -H "x-api-key: YOUR_API_KEY"

Transaction Preview

Show users exactly what they’re about to sign. Transaction simulation catches drainers, malicious approvals, and unexpected asset transfers.

Pre-Signing Simulation

Simulate the transaction before the user signs to reveal what will actually happen.
curl -X POST "https://api.webacy.com/scan/transaction" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "walletAddress": "0xUserAddress...",
    "tx": {
      "from": "0xUserAddress...",
      "to": "0xContractAddress...",
      "data": "0xTransactionData...",
      "value": "0x0"
    },
    "chain": 1,
    "domain": "app.example.com"
  }'
Key response fields:
FieldDescription
assetChanges[]What tokens/NFTs will move and in which direction
riskLevellow, medium, high, or critical
warnings[]Specific risks detected (drainer, phishing, etc.)

EIP-712 Signature Analysis

Permit signatures are the most dangerous attack vector. A user can lose everything without sending a single transaction—just by signing a message.
How Permit Phishing Works: The user signs what looks like a simple message. In reality, they’ve authorized a contract to spend all their tokens. Hours or days later, the attacker drains everything.
curl -X POST "https://api.webacy.com/scan/eip712" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "walletAddress": "0xUserAddress...",
    "msg": {
      "from": "0xUserAddress...",
      "data": {
        "types": {
          "Permit": [
            {"name": "owner", "type": "address"},
            {"name": "spender", "type": "address"},
            {"name": "value", "type": "uint256"}
          ]
        },
        "primaryType": "Permit",
        "message": {
          "owner": "0xUserAddress...",
          "spender": "0xSuspiciousAddress...",
          "value": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
        }
      }
    },
    "domain": "suspicious-site.com"
  }'
The max uint256 red flag: If you see value: "115792089237316195423570985008687907853269984665640564039457584007913129639935", that’s unlimited approval. Always flag this for users.

Phishing Protection

If your wallet has a dApp browser, you need URL screening.

URL Scanning

Check URLs before allowing users to connect their wallet.
curl -X POST "https://api.webacy.com/url/check" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://uniswap-claim.com"}'

Approval Management

Help users understand and manage their existing token approvals.

Get Risky Approvals

Show users their current approvals and highlight dangerous ones.
curl -X GET "https://api.webacy.com/wallets/0xUserAddress.../approvals?chain=eth" \
  -H "x-api-key: YOUR_API_KEY"
Help users clean up:
  • Show unlimited approvals prominently
  • Flag approvals to contracts that no longer exist
  • Identify approvals to known drainer contracts
  • Provide easy revoke functionality

Complete Integration Workflow

Send Flow

Transaction Signing Flow

Full TypeScript Implementation

import { ThreatClient, Chain } from '@webacy-xyz/sdk';

const client = new ThreatClient({
  apiKey: process.env.WEBACY_API_KEY,
  defaultChain: Chain.ETH,
});

// Send flow protection
async function validateSendAddress(address: string, chain: Chain) {
  // 1. Address poisoning (most critical)
  const poisoning = await client.addresses.checkPoisoning(address, { chain });
  if (poisoning.is_poisoned) {
    return {
      allowed: false,
      severity: 'critical',
      reason: 'Address poisoning attack detected',
      details: 'This address looks similar to legitimate addresses and may be part of a scam.'
    };
  }

  // 2. Sanctions check (compliance)
  const sanctions = await client.addresses.checkSanctioned(address, { chain });
  if (sanctions.is_sanctioned) {
    return {
      allowed: false,
      severity: 'critical',
      reason: 'Sanctioned address',
      details: 'This address is on the OFAC sanctions list.'
    };
  }

  // 3. Quick profile (risk assessment)
  const profile = await client.addresses.getQuickProfile(address, { chain });

  if (profile.riskLevel === 'critical') {
    return {
      allowed: false,
      severity: 'critical',
      reason: 'Extremely high risk address',
      riskScore: profile.riskScore
    };
  }

  if (profile.riskLevel === 'high') {
    return {
      allowed: true,
      severity: 'high',
      requireConfirmation: true,
      reason: 'High risk address detected',
      riskScore: profile.riskScore
    };
  }

  return {
    allowed: true,
    severity: profile.riskLevel,
    riskScore: profile.riskScore
  };
}

// Transaction preview
async function previewTransaction(
  userAddress: string,
  txData: { to: string; data: string; value: string },
  chain: number,
  dappDomain?: string
) {
  const simulation = await client.scan.scanTransaction(userAddress, {
    tx: {
      from: userAddress,
      to: txData.to,
      data: txData.data,
      value: txData.value,
    },
    chain,
    domain: dappDomain,
  });

  return {
    riskLevel: simulation.riskLevel,
    warnings: simulation.warnings,
    assetChanges: simulation.assetChanges,
    shouldBlock: simulation.riskLevel === 'critical',
    requiresExtraConfirmation: simulation.riskLevel === 'high',
  };
}

// Signature analysis
async function analyzeSignature(
  userAddress: string,
  typedData: object,
  dappDomain: string
) {
  const result = await client.scan.scanEip712(userAddress, {
    msg: {
      from: userAddress,
      data: typedData,
    },
    domain: dappDomain,
  });

  return {
    riskLevel: result.riskLevel,
    messageType: result.messageType,
    shouldBlock: result.riskLevel === 'critical',
    isPermit: result.messageType?.toLowerCase().includes('permit'),
  };
}

// URL screening for dApp browser
async function checkDappUrl(url: string) {
  const result = await client.url.check(url);

  return {
    safe: !result.isPhishing && !result.isMalware,
    isPhishing: result.isPhishing,
    isMalware: result.isMalware,
    riskScore: result.riskScore,
    categories: result.categories,
  };
}

Example Addresses for Testing

Address Poisoning

AddressChainDescription
0xd9A1C3788D81257612E2581A6ea0aDa244853a91ETHKnown poisoned address ($68M WBTC attack)
0x5f90e59d0a03fd2f8c56b8cc896c5b42594eb3a0ETH$50M address poisoning drain

Sanctioned Addresses

AddressChainAttribution
0x098B716B8Aaf21512996dC57EB0615e2383E2f96ETHLazarus Group (Ronin Bridge)
0x566f827a4988d4a3eb9da469d8d3d0b536da196eETHOFAC SDN List

Phishing & Drainers

AddressChainAttribution
0x84672cc56b6dad30cfa5f9751d9ccae6c39e29cdETHPermit phishing drainer
0xe7d13137923142a0424771e1778865b88752b3c7ETHWalletConnect phishing campaign
0x624Fc3Dc249E37E8BFd3e834C4dF81Ff2dA1D0CaBSCMalicious Permit scammer

Clean Addresses (for comparison)

AddressChainDescription
0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045ETHVitalik’s wallet (low risk)

API Quick Reference

EndpointUse CaseResponse Time
GET /addresses/{address}/quick-profileFast risk assessment~200ms
GET /addresses/{address}/poisoningAddress poisoning check~300ms
GET /addresses/sanctioned/{address}Sanctions screening~100ms
POST /scan/transactionTransaction simulation~500ms
POST /scan/eip712Signature analysis~300ms
POST /url/checkURL screening~200ms
GET /wallets/{address}/approvalsToken approvals~400ms

Next Steps