-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
Check existing issues
- I checked there isn't already an issue for the bug I encountered.
Viem Version
2.28.0
Current Behavior
recoverPublicKey() extracts the v value of a signature in the following way:
const yParityOrV = hexToNumber(`0x${signatureHex.slice(130)}`)
Neither the full length of the signature nor the slice are limited in length. This allows to craft signatures with arbitrary length that still verify successfully.
Expected Behavior
Signatures for which no common on-chain library exists (e.g., OpenZeppelin or Solady) that can parse them into the correct format for the EVM precompile should not verify in viem. Off-chain applications might verify such signatures and then relay them on-chain, leading to failure.
Steps To Reproduce
Consider the following example:
import { http, verifyTypedData, createWalletClient } from 'viem'
import { anvil } from 'viem/chains'
export const account = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
export const walletClient = createWalletClient({
transport: http(),
chain: anvil
})
export const domain = {
name: 'Test',
version: "1",
chainId: 31337,
verifyingContract: '0x0000000000000000000000000000000000000000',
} as const
// The named list of all type definitions
export const types = {
Test: [
{ name: 'test', type: 'string' }
],
} as const
const message = {
test: "Test",
} as const
walletClient.signTypedData({
account,
domain,
types,
primaryType: 'Test',
message,
}).then((signature) => {
console.log(signature)
})
This creates the following signature with the private key of the first default account in anvil:
0xa68c42a14d6c8ededb487f667310f66c120546407f86808254178d96372771f26b74212b32e6f91878f0b179d41f8768fe3d7d34a612c29590cc448a1749eda81b
We can modify the last byte by left-padding an arbitrary amount of 0s:
0xa68c42a14d6c8ededb487f667310f66c120546407f86808254178d96372771f26b74212b32e6f91878f0b179d41f8768fe3d7d34a612c29590cc448a1749eda8001b
This modified signature is still verified correctly:
verifyTypedData({
address: account,
domain,
types,
primaryType: 'Test',
message,
signature: "0xa68c42a14d6c8ededb487f667310f66c120546407f86808254178d96372771f26b74212b32e6f91878f0b179d41f8768fe3d7d34a612c29590cc448a1749eda8001b",
}).then((valid) => {
console.log(valid) // returns true
})
Link to Minimal Reproducible Example
No response
Anything else?
Cannot link a reproducible example as I couldn't find a public RPC that supports eth_signTypedData_v4.