Ronin Network Exploit: Uninitialized Parameter Led to $12M Loss

Ronin Network Exploit: Uninitialized Parameter Led to $12M Loss

Simeon Cholakov
9 min read

Introduction to Ronin Network Bridge

Ronin Bridge is an application for bridging ERC20 tokens and NFTs (non-fungible tokens) between Ethereum and the Ronin chain.

Ronin Bridge is a multi-signature bridge, which means that multiple bridge operators must approve a transaction before it is finalized. This approach ensures a high level of security for cross-chain transactions, preventing any single party from acting maliciously or making unauthorized changes.


Multi-signature bridges and How does Ronin Network work

This section provides a brief introduction to multi-signature bridges and their operation within the Ronin Network. If you are already familiar with the topic, feel free to skip this part.

A multi-signature (multi-sig) bridge in Web3 refers to a mechanism used to securely transfer assets or data between different blockchain networks, requiring multiple cryptographic signatures from authorized participants to approve and execute transactions.

The Ronin-Ethereum bridge facilitates secure and reliable cross-chain transactions between Ronin and Ethereum, managed by 22 bridge operators. Each operator verifies the validity of transactions and votes to approve or reject them. For a transaction to be executed, at least 70% of the operators must approve it, ensuring a high level of security and consensus. This thorough vetting process reduces the risk of fraudulent or erroneous transfers and maintains the integrity of the bridge.

Ronin Validator Set diagram

Attack Analysis

Ronin Network suffered a major exploit on August 6, 2024, in their Bridge contract, involving approximately $12M. Fortunately, the attacker was a whitehat who returned the stolen assets. The exploit involved two transactions on the Ethereum Mainnet.

The root cause of the exploit was a failure to properly initialize the operator weight configuration during the deployment of the latest Ronin Bridge V2 contract. The minimumVoteWeight parameter was set to zero, allowing any signature to pass cross-chain verification.

This is the second hack of the protocol; it was previously hacked in March 2022, resulting in the theft of approximately $600 million. The previous post-mortem can be found here.

Vulnerability Exploitation

Before starting with the Vulnerability Exploitation it is very important to pay attention to the following tweet by the Security Researcher @0xSimao, also known as 0x73696d616f.

Some protocols operate with huge amounts of funds from their customers but do not always take their security seriously. As a result, whitehat hackers are incentivized to exploit these protocols and return the stolen assets to receive compensation for their valuable time and effort. For instance, the whitehat hacker who exploited the vulnerability received a $500M bounty from the protocol as a reward.

These hackers understand that the chances of receiving nothing after investing hours in analyzing the protocol's codebase are very high.

Therefore, it is crucial for all protocols to take their security seriously.

Now, let's start with the Vulnerability Exploitation:

The Ronin Bridge uses the Transparent Upgradable Proxy pattern, a smart contract proxy pattern that allows a contract to be upgraded via an associated ProxyAdmin instance, ensuring only the admin can upgrade the proxy while other calls are transparently forwarded to the implementation contract.

On August 6, 2024, at 08:48:47 AM UTC, the Ronin team updated their proxy twice, moving the version of the proxy from 2 to 4, adding two separate initialize functions.

Update transaction state changes

In the new implementation, two separate initialize functions were added (initializeV3 and initializeV4).

initializeV3 and initializeV4 functions

The issue arose because, during the update transaction process, only the initializeV4 function was executed, skipping the initializeV3 function leaving _totalOperatorWeight uninitialized and defaulting to 0.

Update transaction Invocation flow

Previous versions of the Ronin Bridge fetched totalWeight from the MainchainBridgeManager contract, meaning that the _totalOperatorWeight variable should have been reinitialized. However, due to incorrect proxy initialization in the update transaction, the _totalOperatorWeight variable was left uninitialized and equaled 0.

_totalOperatorWeight state

The MEV bot found this exploit transaction in the pool, leading the whitehat hacker to execute the attack transaction at 9:37:23 AM UTC, only 48 minutes after the update.

Let’s analyze the first and largest of the two attack transactions, where the attacker stole approximately 4000 ETH:

The attacker structured a Malicious Smart Contract which was used to call the fallback function of the abstract Proxy contract used to delegate all calls to another contract using the EVM instruction delegatecall.

In this case the attacker delegated the call to the MainchainGatewayV3 contract calling the submitWithdrawal function with the following input:

Input data

The submitWithdrawal function calls the _submitWithdrawal function, which calls _computeMinVoteWeight to extract the minimumWeight and locked variables.

_submitWithdrawal() function

The latest upgrade of Ronin Bridge stores the total weight in the contract's storage under the variable _totalOperatorWeight, which was set to _totalWeight when _getTotalWeight was called.

_getTotalWeight() and _computeMinVoteWeight() functions

This set the _totalWeight to 0 because of the uninitialized _totalOperatorWeight .

_getTotalWeight() call which returned _totalWeight = 0

Afterward, _minimumVoteWeight is called with _totalWeight to set the _weight variable. This value is then returned and assigned to minimumWeight in _submitWithdrawal.

_minimumVoteWeight() call

Because _totalWeight was 0, _minimumVoteWeight returned 0, setting the minimumWeight to 0.

_locked returned false, making locked in _submitWithdrawal also false.

_computeMinVoteWeight() return amounts

Because both weight and minimumWeight were 0, the subsequent check successfully passed, causing the passed variable to be set to true. This prevented the function from reverting and allowed handleAssetOut to be called.

handleAssetOut was called with the stolen amount of 4000 ETH.

handleAssetOut call

In handleAssetOut, send() was called, transferring approximately 4000 ETH to the attacker address.

handleAssetOut function

This hack highlights a common operational issue involving misconfiguration or uninitialized parameters during the deployment of the latest contract upgrade. This oversight allowed MEV bots to exploit the minimumVoteWeight condition, enabling them to withdraw assets without requiring a signature.

How the attack could have been prevented

The attack on the Ronin Network Bridge could have been prevented through several measures, such as ensuring proper initialization of all critical parameters during the contract upgrade.

Additionally the contract was deployed without being audited. Conducting comprehensive security audits by third-party experts before deploying contracts to the mainnet can identify potential vulnerabilities. Also rigorous testing, including fuzz testing and simulation of potential attack vectors, could help uncover vulnerabilities that might be missed during standard testing procedures.

Consequences

The immediate consequence of this attack was the loss of approximately $12 million. Fortunately, it was exploited by a whitehat hacker, meaning that all user funds will be recovered. However, this incident has undoubtedly impacted user trust and the protocol's reputation, as it is the second hack. Additionally, such exploits can lead to broader market instability, especially if users lose confidence in the security of DeFi protocols.

The Ronin Chain Protocol Response

Around 38 minutes after the exploit at 10:15:23 AM UTC, the contract was paused, and an investigation began. The group of highly trusted security professionals and volunteers SEAL 911, assisted the Ronin team with the process of returning funds.

Some hours after the exploit the Ronin Network team announced that the ETH (~$10 M) had been returned and that they expected the USDC(~$2 M) to be returned later in the day. Additionally, they rewarded the whitehats with a $500K bounty and announced that the network would undergo an audit before being reopened.

Addresses

Attacker Malicious Contract:

Exploited Contract:

Exploit Transactions