Platform: Code4rena
Start Date: 21/06/2022
Pot Size: $55,000 USDC
Total HM: 29
Participants: 88
Period: 5 days
Judge: gzeon
Total Solo HM: 7
Id: 134
League: ETH
Rank: 34/88
Findings: 3
Award: $240.35
π Selected for report: 0
π Solo Findings: 0
π Selected for report: kenzo
Also found by: 0x29A, GimelSec, Lambda, StErMi, cccz, csanuragjain, kirk-baird, sashik_eth, shenwilly
https://github.com/code-423n4/2022-06-illuminate/blob/main/marketplace/ERC5095.sol#L100 https://github.com/code-423n4/2022-06-illuminate/blob/main/marketplace/ERC5095.sol#L116
It doesn't spend _allowance
in marketplace/ERC5095.sol
. Attackers can call withdraw
, redeem
multiple times as the holder.
In withdraw
, redeem
of ERC5095.sol check the _allowance
:
require(_allowance[holder][msg.sender] >= underlyingAmount, 'not enough approvals');
But in authRedeem
it just burns tokens and it doesn't spend _allowance
. If Alice approves Bob 100 amounts, Bob can spend 100 amounts again and again to call withdraw
and redeem
.
None
Spend _allowance
:
_setAllowance(owner, spender, currentAllowance - amount);
#0 - KenzoAgada
2022-06-28T06:28:38Z
Duplicate of #245
29.8781 USDC - $29.88
https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L205
In lend
, the y
is fully controlled by users. Attackers can steal users' tokens if an attacker gives malicious y
to users.
y
and gives it to Bob (victim).lend
of L192 with malicious y
, y
can easily craft values to bypass the checks in lend
.yield
function will transfer token to y
(L651): Safe.transfer(IERC20(u), y, a);
Moreover, Alice can trigger reentrancy attacks to call lend
again in y
(e.g. yield
call IYield(y).sellBase(r, returned);
to reenter lend
). If Bob just set a little a
(e.g. 20 amount) of lend
, but Bob is very trust Illuminate and set approve max to Illuminate protocol, Alice can trigger reentrancy attack to cal lend
multiple times, and amplify total amount to x10 even x100 times.
None
Check yield
addresses should be official, or use allowlist to prevent malicious yields.
#0 - sourabhmarathe
2022-06-29T12:35:53Z
Duplicate of #349.
π Selected for report: defsec
Also found by: 0x1f8b, 0x29A, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xkowloon, 0xmint, Bnke0x0, BowTiedWardens, Chom, ElKu, Funen, GalloDaSballo, GimelSec, IllIllI, JC, Kenshin, Kulk0, Lambda, Limbooo, MadWookie, Metatron, Picodes, Soosh, StErMi, TomJ, WatchPug, Waze, Yiko, _Adam, ak1, asutorufos, aysha, bardamu, catchup, datapunk, delfin454000, dipp, fatherOfBlocks, grGred, hake, hansfriese, hyh, joestakey, kebabsec, kenzo, kirk-baird, oyc_109, pashov, poirots, rfa, robee, saian, sashik_eth, shenwilly, simon135, slywaters, z3s, zeesaw, zer0dot
63.9425 USDC - $63.94
https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L687
scheduleWithdrawal
should have a timeout. Admin can call scheduleWithdrawal
in the beginning to bypass time lock.
In scheduleWithdrawal
, it will set block.timestamp + HOLD;
. But admin can call withdraw
anytime by calling scheduleWithdrawal
in the beginning to bypass timelock.
None
scheduleWithdrawal
should have a timeout:
function scheduleWithdrawal(address e) external authorized(admin) returns (bool) { uint256 when = block.timestamp + HOLD; withdrawals[e] = when; timeout[e] = when + TIMEOUT; emit ScheduleWithdrawal(e, when); return true; } function blockWithdrawal(address e) external authorized(admin) returns (bool) { withdrawals[e] = 0; timeout[e] = 0; emit BlockWithdrawal(e); return true; } function withdraw(address e) external authorized(admin) returns (bool) { uint256 when = withdrawals[e]; require (when != 0, 'no withdrawal scheduled'); require (block.timestamp >= when, 'withdrawal still on hold'); require (block.timestamp < timeout[e], 'timeout'); withdrawals[e] = 0; timeout[e] = 0; IERC20 token = IERC20(e); Safe.transfer(token, admin, token.balanceOf(address(this))); return true; }
#0 - sourabhmarathe
2022-06-30T00:15:12Z
This mitigation does not work well in the event that the admin
is malicious. In such a scenario, the HOLD
value would not matter, as the admin
would be able to withdraw funds regardless. As a result, this issue is not considered a critical issue.
#1 - JTraversa
2022-07-06T23:48:29Z
To clarify, the continued lack of a withdrawal after queing one would indicate that the admins may be being malicious. That said, the blockWithdrawal method generally covers this use case, but the suggestion might be a decent QA one? Unsure.