Skip to content

fix: only scan send payees for address poisoning - #9943

Draft
adonesky1 wants to merge 2 commits into
mainfrom
fix/address-poisoning-send-recipients-only
Draft

fix: only scan send payees for address poisoning#9943
adonesky1 wants to merge 2 commits into
mainfrom
fix/address-poisoning-send-recipients-only

Conversation

@adonesky1

@adonesky1 adonesky1 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Explanation

Restrict address poisoning known recipients to user-chosen send payees so confirmed approves, swaps, and contract calls stop putting token and protocol addresses into the comparison set.

Summary

Export getSendRecipients and hydrate the phishing known-recipient set from it instead of getEffectiveRecipient, which falls back to txParams.to for every non-transfer type.

Problem

Address poisoning is a payee mixup: the user previously sent to Alice, an attacker grinds a lookalike EOA, and the user pastes from history. We were also storing token, Permit2, router, and other contract to values from confirmed approves and contract interactions. Vanity token factories (shared prefix plus suffix) then 4+4-matched each other, which is what fired on the o1.exchange Permit2 approve (dogue vs another B20 token).

getEffectiveRecipient is the right helper for first-time interaction (the contract to is who we are calling). It is the wrong helper for poisoning.

Solution

Add getSendRecipients next to getEffectiveRecipient and use it only for poisoning hydration.

Included:

  • simpleSend to, preferring txParamsOriginal when present
  • Decoded to / _to for ERC-20/721/1155 transfer methods (no fallback to the token contract)
  • swapAndSendRecipient
  • Nested batch calls that themselves are sends or token transfers
  • Untyped transactions with no calldata, treated as legacy native sends

Not included: approves, Permit2, swaps, bridges, staking, and other contract interactions.

getEffectiveRecipient is unchanged so first-time interaction keeps using the contract to.

Follow-up client PR: MetaMask/metamask-extension#45724

Mobile confirmations already type-gate; they pick up the known-set fix when this phishing-controller version is bumped.

Risk

  • Existing known sets that currently contain token/router addresses will drop those entries on next hydration (confirmed tx replay). That is the intended fix.
  • A later send to a lookalike EOA will no longer match against a token the user only approved, which is correct.
  • Clients still on the old phishing-controller keep the old known set until they bump.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Confirmed approves, swaps, and contract calls were adding token and
protocol addresses to the known-recipient set, which made vanity token
contracts look like poisoning matches. Only hydrate and compare against
user-chosen send payees.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant