Full Report
Sometimes, security bugs do not come from an individual issue but the combining of technologies together without considering the implications. There are two separate contracts in this story: Multicall and ERC2771. Multicall is a method of calling multiple functions within a contract at a given time. This is useful because it saves on gas when performing multiple calls at once. ERC-2771 is a standard for meta-transactions. This standardizes how the caller address should be resolved for calls that are made by a trusted relayer, when the user cannot sign the contract. In the ERC2771Context implementation, this is done by overriding the msgSender() and msgData() functions. So, what's the issue? When these two contracts are combined, the address is spoofable. By going through the trusted forwarder with a multicall(), we can make the addresses be spoofed to the victim. By making the address one of the victim, we can act on behalf of them. I love bugs that are not a vulnerability in a single thing but from a result of joining things together.
Analysis Summary
# Vulnerability: Arbitrary Address Spoofing via ERC2771Context and Multicall Integration
## CVE Details
- **CVE ID**: CVE-2023-49145 (Associated with Thirdweb and OpenZeppelin identified patterns)
- **CVSS Score**: 9.8 (Critical)
- **CWE**: CWE-20: Improper Input Validation / CWE-670: Always-Incorrect Control Flow Implementation
## Affected Systems
- **Products**: Smart contracts utilizing both OpenZeppelin Contracts (or similar implementations) and Thirdweb frameworks.
- **Versions**:
- OpenZeppelin Contracts 4.x (prior to 4.9.4)
- OpenZeppelin Contracts 5.x (prior to 5.0.1)
- Various Thirdweb pre-built contracts (specifically those combining these two features).
- **Configurations**: Contracts that inherit from both `Multicall` and `ERC2771Context` (Meta-transactions) and utilize a trusted forwarder.
## Vulnerability Description
The vulnerability is a "logic integration error" that occurs when combining two separate standards:
1. **ERC-2771**: A standard for meta-transactions where a "Trusted Forwarder" passes the original user's address appended to the end of the `msg.data` (the last 20 bytes). The contract uses `_msgSender()` to extract these bytes when the caller is the forwarder.
2. **Multicall**: A utility that allows batching multiple function calls into a single transaction by iterating over an array of data and performing `delegatecall` or `call` on `address(this)`.
**The Flaw**: When a user calls a `multicall()` function via a Trusted Forwarder, the `msg.data` containing the authenticated user's address is stored at the end of the multicall transaction. However, the individual sub-calls inside the multicall are executed without the forwarder's context. An attacker can craft a malicious `multicall` payload where they manually append an arbitrary address to the end of the inner call data. Because the contract sees the `multicall` itself came from a Trusted Forwarder, the `_msgSender()` logic incorrectly extracts the attacker-supplied address from the inner call's data, allowing the attacker to spoof any identity.
## Exploitation
- **Status**: **Exploited in the Wild**. Significant losses reported (e.g., 84.59 ETH, 17,394 USDC in specific transactions).
- **Complexity**: Low to Medium
- **Attack Vector**: Network (Blockchain)
## Impact
- **Confidentiality**: None
- **Integrity**: **Critical** (Attackers can perform any action on behalf of any user, including draining funds or administrative changes).
- **Availability**: High (Potential to brick contracts or exhaust funds).
## Remediation
### Patches
- **OpenZeppelin Contracts v4.9.4**: Introduces a fix for the 4.x branch.
- **OpenZeppelin Contracts v5.0.1**: Introduces a fix for the 5.x branch.
- **Thirdweb**: Users of Thirdweb pre-built contracts must upgrade to the latest patched versions via the Thirdweb dashboard or CLI.
### Workarounds
- **Disable Trusted Forwarders**: Immediately remove the "Trusted Forwarder" address from the contract’s whitelist if the contract is not upgradable.
- **Pause Contracts**: If the contract includes `Pausable` functionality, trigger a pause to prevent exploitation during investigation.
- **Revoke Approvals**: Advise users to revoke token approvals to the vulnerable contract addresses.
## Detection
- **Indicators of Compromise**: Monitor for transactions where the `msg.sender` to a `multicall()` function is a Trusted Forwarder, but the internal logic executes actions on behalf of a different, high-value address.
- **Tools**: Use blockchain explorers (e.g., Etherscan, Phalcon) to inspect `multicall` data for unusual appended bytes (extra 20-byte addresses) at the end of sub-call payloads.
## References
- **OpenZeppelin Advisory**: hxxps://www[.]openzeppelin[.]com/blog/arbitrary-address-spoofing-vulnerability-erc2771context-multicall-public-disclosure
- **Thirdweb Security Blog**: hxxps://blog[.]thirdweb[.]com/security-vulnerability/
- **Example Exploit Transaction**: hxxps://explorer[.]phalcon[.]xyz/tx/eth/0xecdd111a60debfadc6533de30fb7f55dc5ceed01dfadd30e4a7ebdb416d2f6b6