feat(phishing-controller): export extractSignatureAddresses for EIP-712 typed-data scanning - #10170
Merged
Conversation
…natureAddresses Address review: take leading 20 bytes (not mod 2^160), exact excludeFields, signer type-dispatch order, and changelog #9875.
…util Document that 0x-hex (odd or even) is isStrictHexString; oversized hex fails to encode rather than signing as a different address.
…ddresses Resolves the `packages/phishing-controller/CHANGELOG.md` conflict caused by the 17.4.0 and 17.4.1 releases landing on main. Keeps the unreleased `extractSignatureAddresses` entry under `[Unreleased]` and restores the released sections beneath it. No source changes; `signature-address-extraction.ts` is untouched.
Two failures surfaced by the first full CI run on this branch: - `lint:misc:check`: reformat two assertions in `signature-address-extraction.test.ts` per oxfmt. No semantic change. - `constraints`: align the `@metamask/eth-sig-util` devDependency with the rest of the monorepo (`^9.0.0`), which eth-json-rpc-middleware, keyring-controller, message-manager and signature-controller all use. The 41 tests in the suite cross-check directly against `TypedDataUtils.encodeData` and pass unchanged under 9.0.0.
… cap Callers can pass maxAddresses (default 10, ceiling 50) so clients can raise the budget later without a core change.
…ler-extract-signature-addresses # Conflicts: # packages/phishing-controller/CHANGELOG.md
Those .github changes are unrelated to extractSignatureAddresses and are not required to merge this PR.
…ler-extract-signature-addresses
The earlier automated conflict resolution also dropped a blank line in a released section. Restore that section verbatim from main so the only changelog delta on this branch is the Unreleased entry.
…ler-extract-signature-addresses # Conflicts: # packages/phishing-controller/CHANGELOG.md # packages/phishing-controller/package.json # yarn.lock
wzrdk3lly
temporarily deployed
to
default-branch
September 10, 2026 15:50 — with
GitHub Actions
Inactive
The changelog check requires user-facing entries to cite the current PR.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fd1bfce. Configure here.
adonesky1
reviewed
Sep 10, 2026
adonesky1
left a comment
Contributor
There was a problem hiding this comment.
LGTM but we should first address #10170 (comment)
…atureAddresses Match isStrictHexString so a signable uppercase 0X prefix is scanned, not dropped.
adonesky1
approved these changes
Sep 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Explanation
Ticket: PSAFE-441
Supersedes #9875 (same change, opened from a core branch so changelog CI can resolve the head). Review comments on that PR were addressed there.
MetaMask validates
eth_signTypedData_v3andeth_signTypedData_v4requests with PPOM, which inspects the address fields of a signature. PPOM's threat data is refreshed on a delay, so an address that has been flagged recently can still be reported as benign, and it does not cover every chain or protocol.Separately, the real-time per-address scan (
/address/evm/scan) is only applied to a few fields today: the tokenverifyingContract, permitspender, and delegationdelegate. Addresses carried in any other field — recipients, makers, tokens, custom protocol fields — receive no real-time scan at all.This change adds a schema-driven extractor that returns up to 10 distinct
address-typed values found in a typed-data message (including nested structs and arrays, matched by declared type rather than field name), and reports when the message could not be fully walked because the address cap, depth limit, or work budget was reached. When PPOM has not already flagged the request, the extracted addresses are passed to the real-time address scan. Results reuse the existing address cache, so fields already scanned elsewhere are not requested again.What this exports
extractSignatureAddresses(typedData, options)— walkstypes/primaryType/message, returns{ addresses, fields, overflow, maxAddresses }ExtractedSignatureAddresses— return typeExtractSignatureAddressesOptions— options:exclude(addresses to skip, e.g. the signer),excludeFields(top-level field names to skip, e.g.spenderwhen already covered by an existing scan),maxAddresses(optional cap override; default 10, hard ceiling 50)DEFAULT_MAX_SIGNATURE_ADDRESSESandMAX_SIGNATURE_ADDRESSES_CEILING— exported so clients can word overflow copy and stay aligned with the default/ceilingSafeguards
maxAddressesup to 50overflow: trueis returned whenever the walk is incomplete so callers can surface a cautionReferences
Changelog
See
packages/phishing-controller/CHANGELOG.md.Checklist
index.tsNote
Medium Risk
Security-adjacent signing flow support: incorrect normalization or missed addresses could weaken typed-data scanning when clients adopt the export, though behavior is heavily tested and bounded with overflow signaling.
Overview
Adds
extractSignatureAddresses, a schema-driven helper that walks EIP-712types/primaryType/messageand collects distinctaddress-typed values (including nested structs and arrays) for downstream real-time address scanning—not hard-coded field names likespenderorto.The function normalizes values the same way signing does (hex/decimal, leading 20 bytes, lowercase dedupe), supports
exclude, top-levelexcludeFields, and a configurable distinct-address cap (default 10, ceiling 50). It returnsaddresses, per-addressfieldsfor alert copy, andoverflowwhen traversal hits caps, depth (12), or a 5000-node budget so clients can warn when not every address was collected.DEFAULT_MAX_SIGNATURE_ADDRESSESandMAX_SIGNATURE_ADDRESSES_CEILINGare exported fromindex.tsalongside the new types.Ships
signature-address-extraction.ts, a large Jest suite (including@metamask/eth-sig-utilparity checks), changelog entry, andeth-sig-utilas a devDependency only—noPhishingControllerwiring in this PR.Reviewed by Cursor Bugbot for commit 732e1c3. Bugbot is set up for automated code reviews on this repo. Configure here.