On December 5, 2023, the prominent Web3 development platform Thirdweb disclosed significant smart contract security vulnerabilities affecting its pre-built contracts. This critical flaw impacted all ERC-20, ERC-721, and ERC-1155 tokens deployed using these specific vulnerable contracts. In the days following the disclosure, tokens deployed with these vulnerable contracts were progressively exploited in a series of attacks, underscoring the severity of the underlying incompatibility.
Understanding the ThirdWeb Smart Contract Vulnerability
The root cause of the ThirdWeb incident lies in the unexpected interaction between two fundamental components of smart contract development: ERC-2771 and OpenZeppelin's Multicall implementation. To fully grasp the vulnerability, it's essential to understand each component individually and then how their interaction created an exploitable pathway.
ERC-2771: Meta-Transactions and Trusted Forwarders
EIP-2771 defines a contract-level protocol that enables Recipient contracts to accept meta-transactions via trusted Forwarder contracts. This standard is crucial for improving user experience by allowing third parties (forwarders) to pay gas fees on behalf of users, abstracting away the need for users to hold native blockchain tokens.
In practice, OpenZeppelin's ERC2771Context is a widely adopted implementation. Its core functionality involves treating the last 20 bytes of calldata from a trusted forwarder as the effective _msgSender(). For developers using this library, the common practice is to replace all direct uses of msg.sender with _msgSender() to ensure compatibility with meta-transactions. Similarly, _msgData() is used to retrieve the original transaction data, excluding the appended sender information.
function _msgSender() internal view virtual override returns (address) {
uint256 calldataLength = msg.data.length;
uint256 contextSuffixLength = _contextSuffixLength();
if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
} else {
return super._msgSender();
}
}
function _msgData() internal view virtual override returns (bytes calldata) {
uint256 calldataLength = msg.data.length;
uint256 contextSuffixLength = _contextSuffixLength();
if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
return msg.data[:calldataLength - contextSuffixLength];
} else {
return super._msgData();
}
}
Multicall: Batching Transactions for Efficiency
Multicall functionality allows users to bundle multiple function calls into a single transaction, significantly reducing gas costs and improving transaction efficiency. OpenZeppelin's MulticallUpgradeable is a popular implementation for this purpose. It takes an array of calldata bytes and performs a delegatecall for each entry, executing them within the context of the calling contract.
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = _functionDelegateCall(address(this), data[i]);
}
return results;
}
(Note: The bug discussed here has since been fixed in later versions of OpenZeppelin's Multicall.)
The Incompatibility: ERC-2771 and Multicall Conflict
The core of the ThirdWeb incident's smart contract vulnerability emerged from a critical inconsistency in how calldata is processed by ERC-2771 and Multicall. ERC-2771 expects the trusted forwarder to pack the message data and sender information together. The recipient contract then uses _msgData() and _msgSender() to correctly unpack this information.
However, the Multicall function, in its vulnerable implementation, was not designed to be compatible with how ERC-2771 packs data for meta-transactions. Specifically, when Multicall processes a batch of calls, it should have correctly extracted the _msgSender() from the initial meta-transaction and then appended this sender information to each individual call's calldata before executing them. This crucial step was missing.
Without the sender information being correctly appended to the calldata within each sub-call processed by Multicall, the ERC-2771 context within the target contract would attempt to unpack sender information from the last 20 bytes of the _msgData() of the sub-call. Crucially, an attacker could control these last 20 bytes. This allowed a malicious actor to craft specific calldata that, when processed by Multicall and then interpreted by an ERC-2771-enabled contract, would execute arbitrary logic with a manipulated _msgSender() value (e.g., an address controlled by the attacker or even a protocol's own pool address). This effectively bypassed the intended security checks and violated the expectations set by both specifications, leading to unauthorized actions.
ThirdWeb Incident: Attack Analysis and Exploitation
Let's examine a real-world example of the ThirdWeb incident's smart contract vulnerability exploitation, using an attack transaction analyzed by BlockSec's Phalcon platform.
The attacker's strategy involved manipulating the _msgSender() to impersonate a Uniswap pool, thereby draining its token balance.
-
Step 1: Initial Token Acquisition. The attacker began by swapping 5 WETH for 3,455,399,346 TIME tokens on a decentralized exchange. This provided the necessary tokens for the subsequent manipulation.
-
Step 2: Malicious Multicall Execution. This is the core of the exploit. The attacker invoked a trusted forwarder with carefully crafted calldata designed to exploit the ERC-2771/Multicall incompatibility. When this calldata was parsed by the
Multicallfunction, it resulted in theburnfunction of the TIME token contract being called. Crucially, due to the vulnerability, the_msgSender()was incorrectly interpreted as the Uniswap Pool address. This allowed the attacker to effectively burn a significant portion of the TIME tokens held by the Uniswap pool, without actual authorization. The BlockSec Phalcon platform provides detailed transaction tracing to visualize this flow.
Transaction trace showing the malicious multicall The image above illustrates how the attacker's
Forwarder.executecall is processed. Themulticallfunction receives an array of bytes, which then leads to theburnfunction being called with the manipulated_msgSender().
Detailed view of multicall parsing and burn function call This detailed view from Phalcon shows the
bytes[]of length 1 being used as data to call the contract, leading to theburnfunction execution under the false_msgSender(). -
Step 3: Price Manipulation. By burning a large quantity of TIME tokens from the Uniswap pool, the attacker drastically reduced the pool's liquidity for TIME. This artificial scarcity caused the price of TIME relative to WETH to skyrocket within the pool.
-
Step 4: Profitable Arbitrage. With the price of TIME artificially inflated, the attacker then swapped their remaining 3,455,399,346 TIME tokens back for 94 WETH, realizing a substantial profit from the manipulated price.
This sequence of events demonstrates a sophisticated attack leveraging a subtle smart contract vulnerability stemming from module incompatibility.
Secure Your Smart Contracts with BlockSec
Don't let hidden incompatibilities expose your project to risks. Our expert auditors conduct comprehensive smart contract audits to identify and mitigate vulnerabilities before they can be exploited.
Best Security Auditor for Web3
Validate design, code, and business logic before launch
Key Takeaways and Lessons from the ThirdWeb Incident
The ThirdWeb incident serves as a critical reminder of the complexities inherent in Web3 security, particularly concerning the interaction of third-party libraries.
- Interoperability Risks: In the rapidly evolving DeFi space, projects heavily rely on a stack of third-party libraries and modules. While these components accelerate development, their interactions can introduce unexpected and covert vulnerabilities. The ThirdWeb incident clearly illustrates that even widely-used, seemingly robust components like OpenZeppelin's
ERC2771ContextandMulticallUpgradeablecan create critical security gaps when their integration isn't meticulously handled. - Deep Technical Auditing is Essential: This type of smart contract vulnerability is not easily caught by superficial checks. It requires deep technical expertise to analyze how different modules process and interpret data, especially calldata, and identify potential inconsistencies. Thorough smart contract auditing, focusing on cross-module interactions and edge cases, is paramount.
- Continuous Monitoring and Incident Response: Even with robust audits, new attack vectors can emerge. Continuous blockchain security monitoring, like that provided by BlockSec's Phalcon, is crucial for detecting suspicious activity in real-time and enabling rapid incident response to minimize damage.
- Beyond Individual Module Security: Developers must think beyond the security of individual components and consider the holistic security posture of their entire smart contract system. How data flows between different modules, how contexts are preserved or altered, and how external calls are handled are all critical considerations.
The ThirdWeb incident underscores the importance of a proactive and comprehensive approach to blockchain security. Relying solely on the reputation of individual libraries is insufficient; the interactions between them must be rigorously scrutinized.
Investigate On-Chain Incidents with Phalcon
BlockSec's Phalcon is the leading Web3 security platform for real-time monitoring, incident response, and in-depth transaction analysis. Understand complex exploits like the ThirdWeb incident with unparalleled clarity.
Read other articles in this series:
- Lead-In: Top Ten "Awesome" Security Incidents in 2023
- #1: Harvesting MEV Bots by Exploiting Vulnerabilities in Flashbots Relay
- #2: Euler Finance Incident: The Largest Hack of 2023
- #3: KyberSwap Incident: Masterful Exploitation of Rounding Errors with Exceedingly Subtle Calculations
- #4: Curve Incident: Compiler Error Produces Faulty Bytecode from Innocent Source Code
- #5: Platypus Finance: Surviving Three Attacks with a Stroke of Luck
- #6: Hundred Finance Incident: Catalyzing the Wave of Precision-Related Exploits in Vulnerable Forked Protocols
- #7: ParaSpace Incident: A Race Against Time to Thwart the Industry's Most Critical Attack Yet
- #8: SushiSwap Incident: A Clumsy Rescue Attempt Leads to a Series of Copycat Attacks
- #9: MEV Bot 0xd61492: From Predator to Prey in an Ingenious Exploit



