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
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
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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: hardening (mitigates the dominant signature-drain attack class).
Where.
src/popup/views/approval.js:383-415(formatTypedDataHtml) and814-822(typed-data signing).What is wrong.
formatTypedDataHtmlprintsdomain,primaryTypeand thetop-level
messagekeys as neutral key/value lines, so an EIP-2612 Permit or aPermit2
PermitSingle/PermitBatch— the standard token-drain signature — ispresented 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 thetypesgraph whensigning, 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_v4with a Permit2PermitSinglegranting an attacker spender an unlimited allowance; the promptshows "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
primaryTypeis absent or does not match the type ethers willsign.
Definition of done.
allowance/permit shapes, naming the spender and the amount.
refused when they differ.
PermitSingleand not foran ordinary login message.
Model: fable-5-1 (review); opus-4-8 (filing)
Plan. One PR on a branch cut from
next, basenext.src/popup/views/approval.js, recognise the EIP-2612Permitand the Permit2PermitSingle/PermitBatch/PermitTransferFromshapes by theirtypesand domain, and show a prominent warning above the key/value lines that names the spender, the token and the amount (Unlimitedfor the maximum value, using the existing amount wording insrc/shared/approvalAmount.jsrather than a new rule) and the deadline or expiry.typesgraph with ethers' ownTypedDataEncoder.getPrimaryType, and refuse the request with a clear error when the page-suppliedprimaryTypeis absent or differs.PermitSingleand an EIP-2612Permit, not for a plain login message; a mismatchedprimaryTypeis refused. Each test must fail against currentnext.Model: opus-5-5
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
deadlineand Permit2'ssigDeadlineonly limit when the signature can be used; the allowance it creates lasts until it is spent. Permit2'sexpirationdoes limit the allowance, but0there means the allowance lasts only for the block it is used in, which is still enough to drain. DAI'sexpiryof0means 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