Platform: Code4rena
Start Date: 04/03/2024
Pot Size: $88,500 USDC
Total HM: 31
Participants: 105
Period: 11 days
Judge: ronnyx2017
Total Solo HM: 7
Id: 342
League: ETH
Rank: 78/105
Findings: 1
Award: $42.78
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Bauchibred
Also found by: 0x11singh99, 0x175, 0xAlix2, 0xDemon, 0xGreyWolf, 0xPhantom, 0xspryon, 14si2o_Flint, Arabadzhiev, Aymen0909, Bigsam, BowTiedOriole, CRYP70, DanielArmstrong, FastChecker, JecikPo, KupiaSec, MohammedRizwan, Norah, Timenov, Topmark, VAD37, adeolu, btk, crypticdefense, cryptphi, givn, grearlake, jnforja, kennedy1030, kfx, ktg, lanrebayode77, n1punp, santiellena, stonejiajia, t4sk, thank_you, tpiliposian, wangxx2026, y0ng0p3, zaevlad
42.7786 USDC - $42.78
https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/transformers/LeverageTransformer.sol#L40-L96 https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/transformers/LeverageTransformer.sol#L123-L175
The LeverageTransformer.sol
contract has leverageUp
and leverageDown
functions, which are intended to be called from the V3Vault.sol
contract. However, the mentioned functions lack proper msg.sender
validation, which allows malicious contracts to call those functions and steal stuck funds on the contract.
For a malicious contract to steal stuck funds, the following things must be true about the state of the contract.
asset()
and borrow()
and call the leverageUp
or leverageDown
function through the malicious contract in a way that enables them to steal the stuck funds.function leverageUp(LeverageUpParams calldata params) external { uint256 amount = params.borrowAmount; address token = IVault(msg.sender).asset(); IVault(msg.sender).borrow(params.tokenId, amount); [...] // send leftover tokens if (amount0 > added0) { SafeERC20.safeTransfer(IERC20(token0), params.recipient, amount0 - added0); } if (amount1 > added1) { SafeERC20.safeTransfer(IERC20(token1), params.recipient, amount1 - added1); } if (token != token0 && token != token1 && amount > 0) { SafeERC20.safeTransfer(IERC20(token), params.recipient, amount); } }
function leverageDown(LeverageDownParams calldata params) external { address token = IVault(msg.sender).asset(); [...] IVault(msg.sender).repay(params.tokenId, amount, false); // send leftover tokens if (amount0 > 0 && token != token0) { SafeERC20.safeTransfer(IERC20(token0), params.recipient, amount0); } if (amount1 > 0 && token != token1) { SafeERC20.safeTransfer(IERC20(token1), params.recipient, amount1); } }
Manual review.
Consider adding a mechanism for checking the msg.sender
and the following check in the code:
require( msg.sender == Vaultaddr )
Invalid Validation
#0 - c4-pre-sort
2024-03-16T10:10:03Z
0xEVom marked the issue as duplicate of #366
#1 - c4-pre-sort
2024-03-18T08:49:15Z
0xEVom marked the issue as high quality report
#2 - 0xEVom
2024-03-18T09:14:13Z
Clear description of the issue, points out both leverageUp
and leverageDown
Mentions precondition:
One of two tokens of the position NFT must be stuck on the contract.
#3 - c4-judge
2024-03-29T01:44:21Z
jhsagd76 changed the severity to QA (Quality Assurance)
#4 - c4-judge
2024-03-29T01:45:37Z
jhsagd76 marked the issue as grade-a
#5 - jhsagd76
2024-03-29T01:45:48Z
L-A