Blockchain platforms rely on precompiled contracts as a key component of their success. These specialized smart contracts provide optimized solutions for specific operations, improving efficiency and security within the blockchain. However, despite their numerous benefits, precompiled contracts also come with their own set of risks and vulnerabilities. This article aims to introduce you to the security risks and incidents where precompiled contracts were the root cause. By examining these incidents, we hope to provide insights into the potential risks associated with precompiled contracts and offer guidance on best practices for mitigating these risks.
Before diving into the specific vulnerabilities affecting various blockchain platforms, it is essential to understand what precompiled contracts are and the role they play in the blockchain ecosystem. Precompiled contracts are a type of smart contract that is optimized to perform certain operations more efficiently than traditional smart contracts. They are typically written in a low-level language and embedded directly into the blockchain protocol by its developers, rather than being deployed by users like standard smart contracts.
The primary goal of precompiled contracts is to handle computationally-intensive tasks that would otherwise be too expensive or slow to execute using traditional smart contracts.
Examples of precompiled contracts in Ethereum, one of the most popular blockchain platforms, include ECRECOVER (for recovering the signer's Ethereum address from a digital signature), SHA256 (for performing the SHA-256 hashing algorithm), RIPEMD-160 (for implementing the RIPEMD-160 hashing algorithm), and Identity (for copying input data to the output).
Despite their numerous advantages, precompiled contracts have proven to be susceptible to various risks and vulnerabilities. In the following sections, we will explore specific incidents involving precompiled contracts and potential pitfalls associated with their use in blockchain platforms.
Moonbeam has precompiled contract which enable interaction with the native token using a ERC20 standard interface. Using this precompiled code, user can use ERC20 token’s methods such as ‘approve’ or ‘transferFrom’. Following code is the example of precompiled ERC20 methods (approve)
The vulnerability was discovered by pwning.eth, who noticed that the precompiled methods do not account for the delegate call that can cause the caller of the methods to change from the expected caller. The delegateCall allows a smart contract to execute a function call in the context of another contract.
For instance, if a malicious user makes a call to the flashloan function of the DEX contract, they can execute precompiled code using the delegateCall. This means that the user can impersonate the DEX contract and transfer or approve the DEX’s native token.
The project team fixed this issue by restricting the delegated call to the precompiled code whose address is more than 0x9.
BSC uses IAVL tree to validate the cross chain token transfer. To verify that the payload is valid, the provided data’s merkle hash should be equal to the root hash, and also, the data should be included is the IAVL tree.
Verifying the IAVL tree’s merkle hash is relatively expensive computation. The BSC team implemented the validateMerkleProof(0x65) precompiled contract to validate the IAVL trees’s merkle hash and its inclusion.
The calculation of the root hash relies on the Cosmos’s IAVL tree implementation code. The proof nodes are hashed together to generate root hash using the Hash function.
When the left node is null(0), the calculation of the hash is correctly implemented. However, when the left node has value, the right node was ignored in hash calculation. That means a malicious prover can pass the root hash check with arbitrary payload by purposely setting the right node with the arbitrary payload.
The project team fixed the issue by checking the right node is null when the left node is null.
The Statemind team found the security issue on the Avalanche’s precompiled function “NativeAssetCall”. The Avalanche C-Chain maintains the ANT(Avalanche Native Token) balance with assetID which can be exported X-Chain. User can check the balance and transfer the ANT using the nativeAssetBalance and nativeAssetCall precompile contracts.
The code executes evm.Call using the provided to address and callData. What is interesting is that the caller of nativeAssetCall is forwarded to the address defined in the call. That means if the user make a call using the contract to the nativeAssetCall, the user can impersonate the contract to other contract.
This issue could've caused a significant risk on the SushiSwap’s Kashi contract. Kashi is a margin trading and lending platform built on top of the BentoBox(vault). User can use the Kashi’s various features using the cook function. The function ingest the array of actions and execute corresponding functions.
The interesting action Kashi provides is ACTION_CALL. This action calls to the other contract with user provided callee address and data. The only restriction is that the callee address should not be its own address and the BentoBox address. If this restriction is bypassed, an arbitrary user can transfer the deposit on the BentoBox because Kashi has the permission to transfer the deposit.
User can set the callee as precompile address of nativeAssetCall to indirectly forward the transfer call to the BentoBox while maintaining the caller address as Kashi’s contract address. This vulnerability also affects the Abracadabra’s Cauldron contract as the project adopts the Kashi contract. The Ava Labs team determined to deprecate the native asset call.
Hedera provides the precompiled token contracts to use the HTS(Hedera Token Service) token be used with ERC20/721 like experience.
However, there were no restrictions on the caller of the precompiles, in results, a malicious user can make a delegated call to the precompiled contract. The attacker targeted accounts used as liquidity pools at multiple DEXes that use Uniswap v2-derived contract code and called the precompile transfer by impersonating the DEX contract.
The Hedera team has implemented the restriction by check whether the execution is via a delegated call and the target precompile is the token execution.
There were two cases where the precompiled contract affected the stability of the project. The first is when the precompiled contract has flaws in the implementation, such that the execution does not follow its expected specifications. The second is when the precompiled contract has unexpected side effects which can be used to exploit projects on the platform. To protect the project from the unexpected security risk of the precompiled contracts, project teams needs to identify the execution flows of the smart contract they using.
- Does the code use the call or delegateCall?
- Is the callee of the outbound call restricted?
- Is the data of the outbound call restricted?
- Is the value of the outbound call restricted?
- Does the smart contract needs to be interacting with the precompiled contract?
- Is the precompiled contract to be used reliable(battle-tested)?
- What is the desirable implementation and the result of the precompiled code?
- What is the contingency plan when the code flows to an unexpected way?
In conclusion, precompiled contracts can introduce significant security risks to projects on the platform. Project teams must thoroughly understand the execution flows of the smart contracts they are using, as well as the precompiled contracts they interact with. Additionally, it is essential to identify potential security risks and have contingency plans in place in case the code flows in unexpected ways. Ultimately, a strong understanding of the code and careful planning can help mitigate the potential risks associated with precompiled contracts.