Skip to content
This repository was archived by the owner on Jun 2, 2025. It is now read-only.

OMGWINNING/replay-sig-poc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SCA/Permit2 sig replay problem

Overview

  1. Most SCA's implement isValidSig as just a wrapper over ECDSA.recover

  2. Permit2's 1271 signature implementation does not fully account for the SCA case:
    a. They use 1271 signatures if claimedSigner (the SCA) has code > 0: https://github.com/Uniswap/permit2/blob/main/src/libraries/SignatureVerification.sol#L26C13-L26C26
    b. In the 712 struct they use, they do not include the origin address for the tokens. See example of how struct is built
    c. They invalidate nonces based on msg.sender which are SCAs
    d. Result: If an owner owns multiple SCAs, the permit signature could be replayable across all his accounts

The attack:

  1. Owner has multiple SCAs. For example, lets use SCA_1 and SCA_2
  2. Owner signs permit from SCA_1 to transfer tokens to attacker
  3. Attacker calls permit2 with sig from step #2, then calls transferFrom to move tokens from SCA_1 to attacker
  4. Attacker calls permit2 replaying sig from step #2 and #3, then calls transferFrom to move tokens from SCA_2 to attacker

If permit2 nonce of SCA_2 < permit2 nonce of SCA_1, max loss amount is min(erc20.allowance(SCA_2, permit2), erc20.balanceOf(SCA_2)) + time bounded by the time ranges specified in the original permit. (Note: If nonces in SCA_1 >> SCA_2, attacker can replay permits from SCA_1 to SCA_2 to increase nonce until nonce(SCA_1) = nonce(SCA_2) + 1. Permits will succeed, but token transfers would fail if SCA_2 did not approve that token to permit2 contract. )

Attack PoC

A generic PoC in test/GenericPoc.t.sol. PoCs were also built for some wallets to demonstrate specific attack, for Alchemy's LightAccount, Biconomy, and Zerodev's Kernel.

If you run into compile errors from building, it's because LightAccount uses solidity >0.8.21 and permit2 forces 0.8.17. Changing LightAccount in lib/ to 0.8.17 fixes the issue

SCAs that this replay attack would work on

  1. LightAccount (PoC included)
  2. Zerodev's Kernel, including Kernel Lite v2.0/Kernel Lite v2.1 (PoC included for base kernel)
  3. Patch wallet's BaseAccount as it's a fork of zerodev's kernel
  4. Biconomy's Smart Contract Wallet (PoC included)
  5. Soul Wallet's Smart Contract Account
  6. eth-infinitism's EIP4337Fallback used with Gnosis Safe
  7. Ambire Wallet's AmbireAccount
  8. zkSync's default AA implementations (full scope unclear)
  9. OKX's SmartAccount isValidSignature
  10. Argent wallet's BaseWallet if configured with TransactionManager as a module for isValidSignature
  11. Fuse Wallet (fork of argent)

Scope, Applications:

a. Permit2, token transfers are replayable. Bounded by token approvals + permit time ranges on initial permit from SCA. (PoC included)
b. Cowswap, trades are replayable if using the 1271 path. But the signature covers token swap output address, and time validity so impact should be low.

Protocols safe from this

  1. Gnosis safe
  2. ERC2612 permit - contains address owner in signed digest
  3. Aave - uses isValidSig for deposit flow, but passes in origin address into the msg digest

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •