harden: typed-data signing shows no warning for allowance-granting shapes and displays a primaryType it does not enforce #400

Closed
opened 2026-09-21 20:37:56 +02:00 by clawbot · 2 comments
Collaborator

Severity: hardening (mitigates the dominant signature-drain attack class).

Where. src/popup/views/approval.js:383-415 (formatTypedDataHtml) and
814-822 (typed-data signing).

What is wrong. formatTypedDataHtml prints domain, primaryType and the
top-level message keys as neutral key/value lines, so an EIP-2612 Permit or a
Permit2 PermitSingle/PermitBatch — the standard token-drain signature — is
presented exactly like a login message, with no highlight of the spender, the
amount, or the deadline. Separately, the screen prints the page-supplied
primaryType, but ethers derives the primary type from the types graph when
signing, so the name shown need not be the type actually signed.

Why it matters. Signature-based approvals (Permit, Permit2) are the dominant
dApp drain vector; the prompt does nothing to distinguish a drain from a login.

Reproduction. A connected page requests eth_signTypedData_v4 with a Permit2
PermitSingle granting an attacker spender an unlimited allowance; the prompt
shows "Typed data (EIP-712)" and plain key/value lines, with no warning.

Acceptable. Recognise the common allowance shapes (Permit, Permit2) and show
a prominent warning naming the spender and amount; refuse or flag the request
when the supplied primaryType is absent or does not match the type ethers will
sign.

Definition of done.

  • The typed-data screen shows a distinct warning for recognised
    allowance/permit shapes, naming the spender and the amount.
  • The primary type displayed is the one ethers signs, or the request is
    refused when they differ.
  • Tests assert the warning appears for a Permit2 PermitSingle and not for
    an ordinary login message.

Model: fable-5-1 (review); opus-4-8 (filing)

Severity: hardening (mitigates the dominant signature-drain attack class). **Where.** `src/popup/views/approval.js:383-415` (`formatTypedDataHtml`) and `814-822` (typed-data signing). **What is wrong.** `formatTypedDataHtml` prints `domain`, `primaryType` and the top-level `message` keys as neutral key/value lines, so an EIP-2612 Permit or a Permit2 `PermitSingle`/`PermitBatch` — the standard token-drain signature — is presented exactly like a login message, with no highlight of the spender, the amount, or the deadline. Separately, the screen prints the page-supplied `primaryType`, but ethers derives the primary type from the `types` graph when signing, so the name shown need not be the type actually signed. **Why it matters.** Signature-based approvals (Permit, Permit2) are the dominant dApp drain vector; the prompt does nothing to distinguish a drain from a login. **Reproduction.** A connected page requests `eth_signTypedData_v4` with a Permit2 `PermitSingle` granting an attacker spender an unlimited allowance; the prompt shows "Typed data (EIP-712)" and plain key/value lines, with no warning. **Acceptable.** Recognise the common allowance shapes (Permit, Permit2) and show a prominent warning naming the spender and amount; refuse or flag the request when the supplied `primaryType` is absent or does not match the type ethers will sign. **Definition of done.** - [ ] The typed-data screen shows a distinct warning for recognised allowance/permit shapes, naming the spender and the amount. - [ ] The primary type displayed is the one ethers signs, or the request is refused when they differ. - [ ] Tests assert the warning appears for a Permit2 `PermitSingle` and not for an ordinary login message. Model: fable-5-1 (review); opus-4-8 (filing)
clawbot added this to the 1.0.0 milestone 2026-09-21 20:37:56 +02:00
Author
Collaborator

Plan. One PR on a branch cut from next, base next.

  • In src/popup/views/approval.js, recognise the EIP-2612 Permit and the Permit2 PermitSingle / PermitBatch / PermitTransferFrom shapes by their types and domain, and show a prominent warning above the key/value lines that names the spender, the token and the amount (Unlimited for the maximum value, using the existing amount wording in src/shared/approvalAmount.js rather than a new rule) and the deadline or expiry.
  • Show the primary type ethers will actually sign, computed from the types graph with ethers' own TypedDataEncoder.getPrimaryType, and refuse the request with a clear error when the page-supplied primaryType is absent or differs.
  • Unit tests: the warning appears for a Permit2 PermitSingle and an EIP-2612 Permit, not for a plain login message; a mismatched primaryType is refused. Each test must fail against current next.
  • Any new on-screen string goes into the README's approval-screen wording if the README lists such strings.

Model: opus-5-5

Plan. One PR on a branch cut from `next`, base `next`. - In `src/popup/views/approval.js`, recognise the EIP-2612 `Permit` and the Permit2 `PermitSingle` / `PermitBatch` / `PermitTransferFrom` shapes by their `types` and domain, and show a prominent warning above the key/value lines that names the spender, the token and the amount (`Unlimited` for the maximum value, using the existing amount wording in `src/shared/approvalAmount.js` rather than a new rule) and the deadline or expiry. - Show the primary type ethers will actually sign, computed from the `types` graph with ethers' own `TypedDataEncoder.getPrimaryType`, and refuse the request with a clear error when the page-supplied `primaryType` is absent or differs. - Unit tests: the warning appears for a Permit2 `PermitSingle` and an EIP-2612 `Permit`, not for a plain login message; a mismatched `primaryType` is refused. Each test must fail against current `next`. - Any new on-screen string goes into the README's approval-screen wording if the README lists such strings. Model: opus-5-5
Author
Collaborator

Deviation from the plan in #414: the warning names the spender, each token and its amount, but no deadline or expiry.

Those fields mean different things in each shape. EIP-2612's deadline and Permit2's sigDeadline only limit when the signature can be used; the allowance it creates lasts until it is spent. Permit2's expiration does limit the allowance, but 0 there means the allowance lasts only for the block it is used in, which is still enough to drain. DAI's expiry of 0 means it never expires. A single date line in the warning would therefore often suggest the permission ends when it does not. The raw fields are still shown in the message lines below the warning.

Model: opus-5-5

Deviation from the plan in https://git.eeqj.de/sneak/AutistMask/pulls/414: the warning names the spender, each token and its amount, but no deadline or expiry. Those fields mean different things in each shape. EIP-2612's `deadline` and Permit2's `sigDeadline` only limit when the signature can be used; the allowance it creates lasts until it is spent. Permit2's `expiration` does limit the allowance, but `0` there means the allowance lasts only for the block it is used in, which is still enough to drain. DAI's `expiry` of `0` means it never expires. A single date line in the warning would therefore often suggest the permission ends when it does not. The raw fields are still shown in the message lines below the warning. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/AutistMask#400