Silo Finance Logic Error Bugfix Review

Immunefi
Immunefi
Published in
6 min readJun 16, 2023

Summary

On April 28th, a veteran whitehat known as @kankodu responsibly disclosed a critical logic error vulnerability to Silo Finance via Immunefi. The vulnerability showcased a potential exploit that could have allowed a malicious hacker to steal assets from the Silo pool contract. The whitehat demonstrated that an attacker could manipulate the interest rate to borrow more funds than should have been allowed by the system. The whitehat assessed the vulnerability and estimated that approximately $3 million could have been lost across various Silo pools on Ethereum if the vulnerability had been exploited in the wild.

Fortunately, thanks to the whitehat’s swift discovery and report via Immunefi, the Silo Finance team was able to quickly remediate the issue.

No user funds were lost, and the whitehat was awarded with a bounty of 100,000 USDC.

What is Silo Finance?

Silo Finance creates permissionless and risk-isolated lending markets which use an isolated-pool approach, where every token asset has its own lending market and is paired against the bridge assets ETH and XAI (Silo’s over-collateralized stablecoin). Lenders in all protocols are only exposed to the risk of ETH and XAI at any given time.

In addition, since all tokens are paired with ETH or XAI, there is only a single market for every token asset, preventing fractured liquidity and allowing greater protocol efficiency. This approach is contrasted with pure lending pair approaches, where a new lending market is created for each additional pairing.

Vulnerability Analysis

The whitehat reported the vulnerability in the Base Silo contract which is responsible for handling the core logic of the lending protocol.

The Silo contract is a lending protocol which allows users to deposit collateral asset tokens to the contract by calling the deposit(…) functionality of the contract. In return, the contract mints the share of tokens to the depositor based on the deposited amount and the total supply of the share and updates the storage state _assetStorage[_asset] with the deposited amount.

The users who deposit the collateral in the contract can borrow other assets from the protocol by using the borrow(…) function, which updates the accrued interest rate of the borrowing asset first and then checks to see if the current contract has enough tokens for the user to borrow. Then, the function transfers the tokens to the user and checks the loan-to-value(LTV) ratio based on the collateral provided.

On a high level, the vulnerability allows an attacker to manipulate the utilization rate of an asset that had zero total deposit to the contract. An attacker can manipulate the utilization rate by donating an ERC20 asset to the contract, and if the attacker had the majority of the shares in the market for that particular asset, borrowing the donated token would inflate the utilization rate of that particular asset. In general, the steps to reproduce this attack:

  1. Determine a market that had 0 total deposits for one of the assets in the market. For example, WETH had 0 total deposits.
  2. Become the majority shareholder for that particular asset by depositing WETH to that market, which will make the totalDeposits for that asset non-zero.
  3. Donate additional WETH to the market, which will allow other users to borrow more WETH than the total deposited WETH, on step 2.
  4. Use another user/address to deposit another asset in the market, to borrow the donated WETH.
  5. In the next block, if accrueInterest() is called, the utilization rate of the attacker's initial deposited amount will be over 100%, which will increase the interest rate to an extremely high value.
  6. Because of this inflated interest rate, the attacker’s initial deposit is valued more than it should be, and it allows the attacker to borrow most of the funds in the market.

At the time of the submission, the WETH total deposit in one of the Silo market was zero. Since the totalDeposits and the balance of the WETH in the contract is zero, the accrued interest rate _accrueInterest(address _asset) for the WETH would also be zero, as there are no borrowers.

In order to manipulate the interest rate of the WETH, the attacker could have deposited a tiny amount of the 10⁵ wei of WETH to the contract using the deposit(…) functionality, which would record the silo.assetStorage[WETH].totalDeposit for WETH to 10⁵ wei.

Then the attacker could manually transfer or donate 1 WETH to the contract which would make a gap between the total deposited amount of WETH the current balance of WETH in the market.

Using another account, tthe attacker could have deposited the 545 LINK tokens to the contract as collateral which is approx (~2WETH of value) and borrowed 1 WETH from the contract, since there is enough liquidity of WETH in the contract to borrow, whereas the storage silo.assetStorage[WETH].totalDeposit doesn’t have enough deposits recorded.

In the next block, due to silo.assetStorage[WETH].totalBorrows being way more than silo.assetStorage[WETH].totalDeposits, which would accrue the interest of amore than 5000 ETH, the 1e5 WETH of collateral that the attacker initially deposited is now worth more than the 5000 ETH, due to the inflated interest rate for the borrowed WETH token.

Proof of Concept (PoC):

The Immunefi team prepared the following PoC to demonstrate the explained vulnerability.

This POC is written for readers to study and test in Forge:

The steps to use this POC is as follows:

  1. Install https://github.com/foundry-rs/foundry
  2. Replace Counter.sol with BugFixReview.sol
  3. Replace Counter.t.sol with BugFixReview.t.sol
  4. Run forge test — match-path test/BugFixReview.t.sol -vvv

This POC will make a local fork on 17139470 and 17139471 and will try to manipulate the interest rate on the first block before stealing funds on the second block. Since the attack occurs over two blocks, we can’t use a flashloan to demonstrate the attack.

What we can do instead is to use deal from Forge to manipulate the attacker contract balance.

BugFixReview.sol

BugFixReview.t.sol

Log output of the POC:

As can be seen from the log output, the POC managed to inflate the interest rate of the WETH, which can be used by the attacker to borrow 450K worth of XAI from the market.

Vulnerability Fix

The project temporarily fixed the vulnerable market after the report was submitted, and after the proper fix is ready, the code is deployed to the mainnet.

The first mitigation that the project implemented was to deposit an asset to the market that had 0 total deposits in the market, which can be seen in this transaction.

However, this deposit only mitigated the vulnerable market temporarily. For the permanent fix, the project implemented a cap in the utilization rate calculation and limited the maximum compounded interest rate to 10k % APR. The former one is to make sure that the utilization rate never exceeds 100% of utilization rate. And the latter is to stop producing yield after compounded interest passes 10%, unless accrueInterest() is being called.

To make sure the fixes that the project implemented are secure and didn’t leave any edge cases, the code went through formal verification from Certora, with added rules that cover this vulnerability. Those rules are:

cantExceedMaxUtilization and interestNotMoreThenMax.

  • cantExceedMaxUtilization is an invariant that guarantees that the utilization rate never exceeds 100%. This means that no one can borrow more than the deposited amount.
  • interestNotMoreThenMax tests the fixes to make sure that the interest rate cannot exceed the max limit.

The details for both of these rules/specs were already published by the project, which you can access in their Github.

The permanent fix can be seen at this address.

For further information regarding the fixes that Silo Finance and Certora made to fix this vulnerability, you can read here and here.

Acknowledgements

We would like to thank @kankodu for doing an amazing job and responsibly disclosing such an important bug. Big props also to the Silo Finance team who responded quickly to the report and patched it.

If you’re a web2 or web3 developer who is thinking about a bug-hunting career in web3, we got you. Check out the Web3 Security Library, and start earning rewards on Immunefi — the leading bug bounty platform for web3 with the world’s biggest payouts.

And if you’re feeling good about your skillset and want to see if you will find bugs in the code, check out the bug bounty program from Silo Finance.

--

--

Immunefi
Immunefi

Immunefi is the premier bug bounty platform for smart contracts, where hackers review code, disclose vulnerabilities, get paid, and make crypto safer.