DoS Vulnerability In Rebalancer.sol: Detailed Analysis

by Omar Yusuf 55 views

Hey guys! Today, we're diving deep into a fascinating vulnerability found in the Rebalancer.sol contract, dubbed "Amusing Chrome Pony." This issue can cause a Denial-of-Service (DoS), disrupting the crucial process of cross-chain liquidity rebalancing. Let's break down what this means and how it works.

Summary

The sendMsg function within Rebalancer.sol has a flaw that can lead to valid rebalancing transactions being reverted. This happens because the function incorrectly accumulates the _amount to transferInfo.size for max transfer size checks, even when the transfer time window has expired. Imagine trying to send funds across different blockchains, but the system keeps saying no, even though you're within the limits. This is essentially what a DoS attack does, and in this case, it's caused by a miscalculation in the code.

Root Cause

The heart of the problem lies in how Rebalancer.sol handles the maxTransferSize limit. Specifically, the sendMsg function updates currentTransferSize[_msg.dstChainId][_msg.token].size by adding _amount even when the time window for transfers has passed (transferSizeDeadline < block.timestamp).

Instead of resetting the transferInfo.size to zero and then checking if _amount is less than _maxTransferSize, it keeps adding to the old size. This means that if a previous transfer occurred and the time window has expired, the accumulated size can exceed the limit, even if the current transfer amount is perfectly valid. It's like trying to fit more water into a glass that's already full – it just spills over, or in this case, the transaction reverts with the error Rebalancer_TransferSizeExcedeed.

This flawed logic leads to an incorrect enforcement of the maxTransferSize limit, preventing legitimate rebalancing transactions from going through. To put it simply, the system is misremembering past transfers and incorrectly applying the size limits.

Internal Preconditions

Before this vulnerability can be exploited, a few things need to be in place within the Rebalancer contract:

  1. Non-Zero maxTransferSize: The contract must be deployed with a maxTransferSize set for a specific destination chain (dstChainId) and token. This is done using the setMaxTransferSize function. Think of this as setting the maximum weight a truck can carry before it leaves the depot.
  2. Previous Transaction: A rebalancing transaction must have already occurred, which sets currentTransferSize[_msg.dstChainId][_msg.token].size to a non-zero value. This is like the truck already having some cargo on board.
  3. Expired Time Window: The transferTimeWindow (default is 86400 seconds, or 24 hours) needs to have expired since the last transfer. So, the transferInfo.timestamp + transferTimeWindow must be less than the current block.timestamp. This is like waiting a day after the initial loading before trying to add more cargo.

External Preconditions

Externally, there's one primary condition that needs to be met for this vulnerability to be triggered:

  1. Rebalancer Interaction: A rebalancer (an entity with the REBALANCER_EOA role) must attempt to call the sendMsg function with a valid _amount. This amount should be less than the maxTransferSize, but when added to the stale transferInfo.size, it exceeds the limit. This is the moment when the truck driver tries to load more cargo, but the combined weight exceeds the limit due to the incorrect calculation.

Attack Path

Let's walk through a scenario to see how this vulnerability can be exploited:

  1. Configuration: The contract is configured with maxTransferSize[_dstChainId][_token] = 1000 * 10^6 (e.g., for USDC) and transferTimeWindow = 86400 seconds. This sets the maximum transfer size for USDC on a specific destination chain to 1,000 million units and the time window to 24 hours.
  2. Initial Transfer: A rebalancer calls sendMsg for _dstChainId and _token (USDC), transferring 800 * 10^6 USDC. This sets currentTransferSize[_dstChainId][_token].size = 800 * 10^6 and transferInfo.timestamp = block.timestamp. Now, 800 million USDC units have been transferred, and the timestamp of the transfer is recorded.
  3. Time Expiry: After 86400 seconds (24 hours), the time window expires. This means transferInfo.timestamp + 86400 < block.timestamp is true.
  4. Second Transfer Attempt: The rebalancer calls sendMsg again with _amount = 300 * 10^6 USDC, which is less than the maxTransferSize of 1000 * 10^6. The rebalancer is trying to transfer 300 million USDC units, which should be allowed.
  5. Incorrect Accumulation: In sendMsg, because the time window has expired, the condition transferSizeDeadline < block.timestamp is true. Instead of resetting the size, the contract updates currentTransferSize[_dstChainId][_token].size += _amount, resulting in 800 * 10^6 + 300 * 10^6 = 1100 * 10^6. The contract incorrectly adds the new amount to the old, stale size.
  6. Transfer Failure: The check require(transferInfo.size + _amount < _maxTransferSize, Rebalancer_TransferSizeExcedeed()) evaluates 1100 * 10^6 > 1000 * 10^6, causing the transaction to revert erroneously. Because the calculated size (1100 million) is greater than the maximum allowed size (1000 million), the transaction fails.
  7. DoS: The rebalancer cannot complete the valid rebalancing transaction, preventing liquidity transfer to the destination chain. The rebalancer is blocked from performing a valid transfer, disrupting the liquidity balancing process.

Impact

The impact of this vulnerability is significant, primarily leading to a Denial-of-Service:

  • Denial-of-Service (DoS): Valid rebalancing transactions are blocked, disrupting the protocol’s ability to maintain liquidity across chains. This is a core function of the Rebalancer, so any disruption here is critical. Imagine the bridges between different blockchains being blocked, preventing the smooth flow of assets.
  • Systemic Risk: A persistent DoS can lead to liquidity imbalances, reducing the protocol’s efficiency and potentially affecting user trust. If the rebalancing mechanism is consistently blocked, it can create imbalances in liquidity pools, making the protocol less efficient and potentially eroding user confidence.
  • No Direct Fund Loss: Importantly, this issue does not cause direct loss of funds, as the Rebalancer cannot transfer user funds. The vulnerability is in the logic of the contract, not in the ability to move funds illicitly.
  • Sherlock Rules Alignment: Per Sherlock’s guidelines, this vulnerability qualifies as Medium severity. This is because it disrupts a core protocol function (rebalancing) without direct fund loss. Section III.3, which covers DoS in time-sensitive operations, further supports the Medium severity assessment.

Mitigation

The solution to this vulnerability is straightforward:

  • Reset Size: Modify the sendMsg function to reset currentTransferSize[_dstChainId][_msg.token].size to zero when transferSizeDeadline < block.timestamp. After resetting, check only if _amount < _maxTransferSize. This ensures that the size is correctly calculated based on the current transfer, rather than being influenced by stale data from previous transfers.

By implementing this fix, the Rebalancer contract will accurately enforce the maxTransferSize limit, preventing valid rebalancing transactions from being erroneously blocked. This will restore the smooth functioning of cross-chain liquidity rebalancing, which is crucial for the protocol’s overall health and efficiency.

In conclusion, the "Amusing Chrome Pony" vulnerability highlights the importance of careful logic in smart contracts, especially when dealing with time-sensitive operations. By understanding the root cause and implementing the recommended mitigation, we can ensure the reliability and efficiency of the Malda protocol.