Apricot Phase 6: Native Asset Call Deprecation
Summary
TL;DR: Funds are safu. Multiple dev teams worked around the clock for the last few days to address a potential issue that is now fixed. This report explains what happened.
Last Sunday on September 4, 2022, we received a report of an issue from the Abracadabra and Sushi developer teams, who, in turn, were tipped off by an anonymous submission on Immunefi. The Native Asset Call precompile, a special feature on the C-Chain that is used to interact with Avalanche Native Tokens, could be abused to trick certain contracts that performed blacklist-protected calls to user-supplied contracts to call undesirable targets. This feature does not exist on the subnet-evm and Subnets are thus unaffected.
We are incredibly happy and grateful to report that with the help and collaboration of the community all funds are safe, the reported issue has not been exploited, the code has been patched, and Avalanche remains stable. Out of an abundance of caution, the Abracadabra and Sushi teams temporarily transferred their users’ funds away from impacted contracts to secure them and will be returning them to their users. You can expect to hear more details from their team soon with how the users’ funds will be returned.
Ava Labs will be rewarding Sushi and Abracadabra for their responsible disclosure with a substantial bounty. If the anonymous submitter on Immunefi chooses to come forward, we will award them as well for the tip that led to the discovery of the bug.
The Issue
Precompile contracts provide a standardized way to add custom functionality into the virtual machine. Such contracts can be called directly by specifying the precompile’s address and passing in the desired input. This feature is typically used to implement cryptographic functionality that would be difficult and expensive to implement in Solidity. Instead, common and well-tested libraries can be used directly to perform these operations efficiently.
The issue in this report comes from a precompile that is unique to the Avalanche C-Chain: Native Asset Call. This precompile is used to offer the same low-level call functionality for Avalanche Native Tokens as is available to the handling of AVAX.
The EVM provides the CALL opcode, which performs two actions:
- Transfer the native coin from the caller to the callee
- If the callee is a contract (or precompile contract), invoke it with specified calldata
Native Asset Call was added to provide the same functionality with the exception that it would perform a transfer of an Avalanche Native Token instead of the native coin of the EVM. It takes as input the following arguments:
- Receiver address
- AssetID of the Avalanche Native Token to transfer
- Amount of the Avalanche Native Token to transfer
- Calldata to pass in to a call to the receiver address
Native Asset Call performed two simple steps (similar to the EVM’s low-level CALL opcode):
- Transfer the Avalanche Native Token to the receiver address
- If the callee is a contract, invoke it with the specified calldata
Vital to the implementation of Native Asset Call is the address used as the calling context, when Native Asset Call invokes the receiver contract.
In order to provide the same functionality as the CALL opcode, the Call must be treated as if it comes from the original caller of Native Asset Call as opposed to Native Asset Call’s own address. Therefore, the caller address is set to the address that directly invoked Native Asset Call.
This makes an important assumption that the caller has explicitly chosen to call the precompile and therefore it should be safe to propagate the caller context. While this assumption holds for every invocation where the caller explicitly decides which address to call, it breaks down in the case of contracts that allow users to provide a callback address and do not filter out this precompile from their blacklist.
For example, this impacted the Abracadabra team’s Cauldron contracts because it provides the functionality to perform low-level calls on behalf of a user after checking that the recipient address of the call is not the BentoBox address or the Cauldron address:
This low-level call, if directed to a Native Asset Call, led to a potential problem because the caller assumed that no callee would preserve the calling context, rendering the validation checks on input arguments ineffective.
Thanks to the Sushi and Abracadabra developers for their hard work to investigate and report this issue and to the anonymous submitter on Immunefi for tipping them off.
The Fix
As soon as the potential issue was reported, the Avalanche platform developers looked into the claims and verified the issue. The primary goal at this point was to protect any and all affected contracts on Avalanche as soon as possible without alerting any potential attacker of the issue.
Ava Labs promptly released a quick patch that prohibited the issuance of any future blocks that contained an interaction with the Native Asset Call as invalid. We then coordinated with node operators around the world to get as much stake on this version as possible. Thanks to the swift action of node operators, a majority of the stake upgraded within a few hours and prevented anyone from performing this interaction.
A new release was planned to provide a cleaner and more elegant fix by deprecating Native Asset Calls altogether. However, this upgrade was implemented incorrectly and failed to deprecate Native Asset Calls, while it disabled the previous patch. If you see a brief reappearance of Native Asset Calls right after the Apricot Phase 6 activation (typically used by auto-compounding bots), that is why. None of these transactions contain an exploit.
To re-address the issue, the developers released a final patch to again refuse future blocks that contained an interaction with the Native Asset Call. Thanks to the swift action of node operators, a majority of stake upgraded within a few hours to prevent anyone from performing this malicious interaction.
At this time, it is impossible to interact with the Native Asset Call precompile on the Fuji Testnet or on Mainnet. All contracts on the Avalanche platform that were open to this exploit are safe, with no need for interaction or modification required on their behalf. AvalancheGo@v1.9.0 will fully deprecate this precompile and introduce a safer replacement to restore full functionality for Avalanche Native Tokens on the C-Chain.
Conclusion
Many thanks to the Abracadabra and Sushi teams and to the entire Avalanche validator community for updating their nodes so promptly over a holiday weekend to prevent an attacker from exploiting this issue. No funds were lost and almost everyone continued to interact with Avalanche throughout the last few days without issue.
Responsible disclosure programs are a critical part of keeping ever-evolving blockchain platforms, like Avalanche, safe and we look forward to continuing to support security researchers through our Bug Bounty Program.
Apricot Phase 6: Native Asset Call Deprecation was originally published in Avalanche on Medium, where people are continuing the conversation by highlighting and responding to this story.