Skip to content

feat(phishing-controller): export extractSignatureAddresses for EIP-712 typed-data scanning - #10170

Merged
adonesky1 merged 15 commits into
mainfrom
psafe-441-signature-address-scan
Sep 10, 2026
Merged

feat(phishing-controller): export extractSignatureAddresses for EIP-712 typed-data scanning#10170
adonesky1 merged 15 commits into
mainfrom
psafe-441-signature-address-scan

Conversation

@wzrdk3lly

@wzrdk3lly wzrdk3lly commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

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_v3 and eth_signTypedData_v4 requests 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 token verifyingContract, permit spender, and delegation delegate. 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) — walks types/primaryType/message, returns { addresses, fields, overflow, maxAddresses }
  • ExtractedSignatureAddresses — return type
  • ExtractSignatureAddressesOptions — options: exclude (addresses to skip, e.g. the signer), excludeFields (top-level field names to skip, e.g. spender when already covered by an existing scan), maxAddresses (optional cap override; default 10, hard ceiling 50)
  • DEFAULT_MAX_SIGNATURE_ADDRESSES and MAX_SIGNATURE_ADDRESSES_CEILING — exported so clients can word overflow copy and stay aligned with the default/ceiling

Safeguards

  • Cap of 10 distinct addresses per message by default, overridable via maxAddresses up to 50
  • Max traversal depth of 12
  • Max 5000 nodes visited
  • overflow: true is returned whenever the walk is incomplete so callers can surface a caution

References

Changelog

See packages/phishing-controller/CHANGELOG.md.

Checklist

  • Tests written and passing
  • Changelog updated
  • Exports added to index.ts
  • Version bump (pending release cut)

Note

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-712 types/primaryType/message and collects distinct address-typed values (including nested structs and arrays) for downstream real-time address scanning—not hard-coded field names like spender or to.

The function normalizes values the same way signing does (hex/decimal, leading 20 bytes, lowercase dedupe), supports exclude, top-level excludeFields, and a configurable distinct-address cap (default 10, ceiling 50). It returns addresses, per-address fields for alert copy, and overflow when traversal hits caps, depth (12), or a 5000-node budget so clients can warn when not every address was collected. DEFAULT_MAX_SIGNATURE_ADDRESSES and MAX_SIGNATURE_ADDRESSES_CEILING are exported from index.ts alongside the new types.

Ships signature-address-extraction.ts, a large Jest suite (including @metamask/eth-sig-util parity checks), changelog entry, and eth-sig-util as a devDependency only—no PhishingController wiring in this PR.

Reviewed by Cursor Bugbot for commit 732e1c3. Bugbot is set up for automated code reviews on this repo. Configure here.

wzrdk3lly and others added 12 commits August 12, 2026 12:37
…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.
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
wzrdk3lly requested review from a team as code owners September 10, 2026 15:50
The changelog check requires user-facing entries to cite the current PR.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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.

Comment thread packages/phishing-controller/src/signature-address-extraction.ts Outdated

@adonesky1 adonesky1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but we should first address #10170 (comment)

…atureAddresses

Match isStrictHexString so a signable uppercase 0X prefix is scanned, not dropped.
@adonesky1
adonesky1 added this pull request to the merge queue Sep 10, 2026
Merged via the queue into main with commit d5fe1fe Sep 10, 2026
58 checks passed
@adonesky1
adonesky1 deleted the psafe-441-signature-address-scan branch September 10, 2026 18:04
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.

2 participants