Blog Post

High Risk Vulnerability Disclosed to Ondo Finance

March 22, 2022

## Introduction

On 26 January 2022, [Ashiq Amien](https://twitter.com/AshiqAmien), a security researcher at iosiro, identified a high risk vulnerability in Ondo Finance affecting the Tranche Token smart contract and surrounding contracts. Under certain conditions, an attacker could exploit this vulnerability to drain $50m from the affected UniswapStrategy contracts. The theft relied on a feature that was intended to be activated at a later time, however, was not enabled during the bug disclosure, so **no user funds were at risk**. The bug was disclosed and remediated on 26 January 2022 and awarded $25,000.


## Bug Details

The TrancheToken contract was an implementation contract used by several minimal proxy contracts. While all of the minimal proxy TrancheToken contracts were initialized, the `TrancheToken` implementation contract itself was uninitialized and vulnerable to having its state permanently impaired from a `selfdestruct` call. This affected all of the TrancheToken proxy contracts as well, which had no default upgrade mechanism to point to a new implementation contract. As a proof of concept, the following vault contract can be created, and its address passed through to the TrancheToken contract in an [initialize()](https://etherscan.io/address/0xb279d1ed3848cee8ba6dba426be620a289ccef10#code#F19#L33) call:


<pre>
<code class="language-solidity">
// This is a fake contract to conform to the TrancheToken implementation contract and set up to call the `destroy()` function
contract Fakevault {
   
   address public registry;
   //need this for the whenNotPaused modifier
   bool public paused = false;
   

constructor() public payable {
       registry = address(this);
   }

   //destroy the contract from this contract's context
   function destroyImpl(address tranche) public {
       ITranche(tranche).destroy(payable(registry));
   }

   receive() external payable {}
   fallback() external payable {}
}
</code>
</pre>


The [initialize()](https://etherscan.io/address/0xb279d1ed3848cee8ba6dba426be620a289ccef10#code#F19#L33) function on the TrancheToken implementation contract can be called, followed by a `destroyImpl()` call on the exploit contract to trigger the `selfdestruct` in the [destroy()](https://etherscan.io/address/0xb279d1ed3848cee8ba6dba426be620a289ccef10#code#F19#L94) function.


```jsx

bytecode before: 0x6080604052...
vault before: 0x0000000000000000000000000000000000000000
vault after: 0x22753E4264FDDc6181dc7cce468904A80a363E44
bytecode after: 0x

```


Since the associated minimal proxies don’t check if the underlying contract has a bytecode length greater than 0, calls to any of the aforementioned proxies no-op, which could lead to issues in dependent contracts.


## Impact

The bug had the following points of impact:


- Permanently brick the state of any of the minimal proxy contracts that use the implementation contract, causing any calls to no-op.

- Permanently brick the state of the implementation contract.

- The [AllPairVault](https://etherscan.io/address/0x2BB8de958134AFd7543d4063CaFAD0b7c6de08BC#code#F20#L54) contract would need to be completely redeployed since the immutable TrancheTokenImpl address permanently points to a bricked contract.

- If the relevant flag, the token minting flag, was set and all relevant contracts were not paused, it would have been possible to drain all assets from all strategy contracts. As the flag was not set at the time of disclosure, no token theft was possible.


The token minting flag is an [admin-controlled boolean](https://etherscan.io/address/0x2BB8de958134AFd7543d4063CaFAD0b7c6de08BC#code#F20#L893) that enables the use of `TrancheTokens` to represent ownership of portions of vaults in the `AllPairVault` contract. Each vault is associated with a `UniswapStrategy` contract that manages Uniswap LP tokens.


In the intended scenario, users can burn their `trancheTokens` and retrieve their associated LP tokens by calling the [AllPairVault.withdrawLp()](https://etherscan.io/address/0x2BB8de958134AFd7543d4063CaFAD0b7c6de08BC#code#F20#L885) function.


In the exploit scenario, where the `TrancheToken` implementation contract is destroyed, all of the calls to [burn a user’s tokens](https://etherscan.io/address/0x2BB8de958134AFd7543d4063CaFAD0b7c6de08BC#code#F20#L896) simply no-op. This is due to the associated minimal proxy above the `TrancheToken` implementation contract that forwards the call and performs no state changes. In this way, an attacker does not need any tokens and can call the `AllPairVault.withdrawLp()` function and retrieve the relevant LP tokens.  A well-crafted contract could drain all vaults in a single transaction, up to the value of $50m at the time of disclosure. Again, since the mint flag was not set, **no user funds were at risk**. Moreover, the Ondo Finance team patched the issue shortly after it was confirmed.


## Conclusion

Thanks to Immunefi for assisting in the disclosure process, and to Ondo Finance for their support during the process and fast response, as well as their eagerness to engage in a bug bounty program.


As an additional precaution to bug bounties, we recommend that projects undergo external audits of their systems before going into production. If you’d like to get your smart contracts audited by an experienced team, reach us at hello@iosiro.com.

Secure your system.
Request a service
Start Now