Full Report
Cryptographic signatures are super useful in Ethereum Solidity smart contracts for proving that a user approves an action. However, it'd be nice to do this for smart contracts but there is no key. So, what to do? ERC-1271 is a specification for calling smart contracts that require signatures. Instead of an actual signatures, it calls a function and verifies the action being performed. Most SCA (Smart Contract accounts) implement ERC-1271 using the similar methods to EOAs. When processing information from a smart contract that was checking the signature for the SCA, it did NOT include the origin contract. This meant that signatures were not specific enough! Why is this bad? If the same address owns multiple SCAs, then there is no discriminator between the two SCAs! So, a replay attack could be used from one SCA to another. Several implementations, including Alchemy's LightAccount, were vulnerable to this issue. When signing data, it's important to be as specific as possible and verify everything possible to prevent these types of issues. Good find!
Analysis Summary
# Vulnerability: ERC-1271 Signature Replay on Smart Contract Accounts (SCA)
## CVE Details
- CVE ID: Not explicitly assigned in the text. (Implied as a critical finding, but no public CVE assigned at the time of the report)
- CVSS Score: Not provided.
- CWE: CWE-362 (Race Condition) or potentially CWE-347 (Improperly Implemented Cryptographic Checks).
## Affected Systems
- Products: Implementations of ERC-1271 within various Smart Contract Accounts (SCAs), including:
- Alchemy's **LightAccount**
- **Zerodev's Kernel**
- **Biconomy** SCAs
- **Soul Wallet** contract
- **eth-infinitism's EIP4337Fallback** for Gnosis Safes
- **AmbireAccount**
- Versions: Affected versions are those implementing the reference ERC-1271 verification logic without incorporating the contract address or other unique context into the signed hash.
- Configurations: Any SCA that implements ERC-1271 by validating messages based solely on the data hash/signature recovery without binding the signature specifically to that originating SCA.
## Vulnerability Description
ERC-1271 allows smart contracts to validate signatures. Many SCAs implemented this standard using a reference implementation that relies on ECDSA signature recovery (`recoverSigner`).
The flaw arises when the signing mechanism used by the SCA does not include the unique identifying context of the SCA itself (i.e., its address) within the data being signed. If a single entity owns multiple SCAs, a signature generated and validated by one SCA can be "replayed" by an attacker against another SCA owned by the same entity, provided both SCAs use the vulnerable ERC-1271 verification method and the application interaction (like Permit2) does not explicitly bind the signature context to the originating SCA address.
For applications like Permit2, where the `owner` address is passed as a call argument rather than being included in the signed structure, a signature valid for an ERC-20 token approval on SCA 'A' could be replayed to authorize the same action on SCA 'B'.
## Exploitation
- Status: PoC available ("replay-sig-poc" provided by the reporter). Not confirmed exploited in the wild against user funds at the time of reporting, and initial impact was assessed as fairly limited.
- Complexity: Low, if the victim owns multiple vulnerable SCAs and interacts with a vulnerable application that relies on these signatures (e.g., Permit2).
- Attack Vector: Network (requires interaction with the vulnerable SCA and application).
## Impact
- Confidentiality: Minimal. Primarily relates to authorization bypass.
- Integrity: **High**. An attacker can replay a valid authorization signature (e.g., a token approval) across multiple accounts controlled by the same user, potentially leading to unauthorized asset movement or allowance grants beyond the user's initial intent.
- Availability: Minimal.
## Remediation
### Patches
Fixes involve modifying the `isValidSignature` implementation in the SCA contract to ensure the signed hash is unique to the specific contract instance. The two primary, adopted solutions are:
1. **Nested EIP-712 Struct Approach (Preferred):** Wrapping the incoming digest with the domain separator and the SCA's address before hashing, ensuring `keccak256(abi.encode("\x19\x01", domainSeparator, digest))` is replaced with a hash that includes the contract address.
solidity
// Example of a fixed logic path (Solution 1 adopted by LightAccount)
bytes32 wrappedDigest = keccak256(abi.encode("\x19\x01", domainSeparator, digest, address(SCA)));
2. **Digest Wrapping (Alternative Lightweight Approach):** Encoding the original digest with the SCA address.
solidity
// Example of Solution 2
bytes32 wrappedDigest = keccak256(abi.encode(digest, address(SCA)));
All involved SCAs have acknowledged the risk or shipped a fix based on these principles.
### Workarounds
Users relying on affected SCAs should verify that the latest deployed contract version incorporates the necessary fix addressing the signature context binding.
## Detection
- Indicators of Compromise: Failed attempts to replay existing signed messages against *other* SCAs owned by the same user, or unexpected execution flows originating from a signature that appears valid across multiple accounts.
- Detection Methods and Tools: Runtime monitoring that checks for inconsistencies in signature verification contexts across the user's deployed SCAs. Automated SCA security scanners should flag non-context-aware ERC-1271 implementations.
## References
- Vendor Advisories: Alchemy, Zerodev, Biconomy, etc., have issued fixes for their respective SCAs.
- Relevant links - defanged:
- ERC-1271 Specification: eips.ethereum.org/EIPS/eip-1271
- PoC Repository: github.com/omgwiNNING/replay-sig-poc
- Information Source Blog: alchemy.com/blog/erc1271-signature-replay-vulnerability