Platform: Code4rena
Start Date: 27/04/2022
Pot Size: $50,000 MIM
Total HM: 6
Participants: 59
Period: 5 days
Judge: 0xean
Id: 113
League: ETH
Rank: 17/59
Findings: 3
Award: $652.94
🌟 Selected for report: 0
🚀 Solo Findings: 0
Loan can be destroyed because of no price reported by oracle. (or any other reason that makes oracle "work as expected" in bad situations when the get
function return success=false
)
According to the interface of INFTOracle, the first parameter returned is boolean success
indicating if the request is successful.
However, this boolean is not checked before rate
is used to determine if the loan is underCollateralized in NFTPairWithOracle
(there are 2 places where use oracle.get
without checking success or not).
This means, the oracle can be "operating normally", and already indicated they can't give a price at the moment by returning success=false, rate=0
. But in this scenario, rate = 0 will be used and all loans will be determined as under collateralized.
(bool sucess, uint256 rate) = loanParams.oracle.get(address(this), tokenId); require(success, "Oracle not up to date");
#0 - cryptolyndon
2022-05-06T04:11:45Z
Confirmed. Duplicate of #21.
🌟 Selected for report: IllIllI
Also found by: 0x1337, 0x1f8b, 0xDjango, 0xf15ers, AuditsAreUS, BowTiedWardens, CertoraInc, Funen, GimelSec, MaratCerby, Ruhum, WatchPug, antonttc, berndartmueller, bobi, bobirichman, broccolirob, catchup, cccz, defsec, delfin454000, gs8nrv, gzeon, horsefacts, hubble, hyh, ilan, jah, joestakey, kebabsec, kenta, kenzo, m9800, mics, oyc_109, pauliax, reassor, robee, samruna, sikorico, simon135, throttle, unforgiven, z3s
75.0312 MIM - $75.03
_lend
when used in through requestAndBorrow
or takeCollateralAndLend
_lend
, it takes an parameter called accepted
and compare it with the state variable tokenLoanParams to make sure the borrower didn't front-run the tx. This is a good check, but in requestAndBorrow
and takeCollateralAndLend
, same parameters are passed in for _requestLoan
and _lend
, considering these are probably the most used function, it would be better to use a boolean call checkLoan to decide if we need this check or not. It will only be needed in lend
function. (or just move the check into a different internal function and call it before lend
)I highly recommend the team to remove the ability to do arbitrary function calls on behalf of the NFTPair contract. Use of arbitrary contract call is a very dangerous pattern, it should be avoided unless there's a very strong motive to support it.
Things that can go wrong with it:
NFTPair
contract to use their asset
. (it should have been approving BentoBox) This can be achieved by calling asset.transferFrom(user, attacker).collateral
suffer the same vulnerability as the tUSD bug and could have lead to huge hack in Compound. The exact bug caused by having 2 entry points to a single contract is unlikely to happen with well-known ERC20s again, but there might be more potential issue similar to this one, and the process of adding collateral will need to be better reviewed, potentially the team should not accept any upgradable contracts.BentoBoxV1
contract, if the team decide to launch this code base on BentoBoxV1 it should be safe, but if the newer version is upgrdable then this mechanism cannot be trusted, because it's possible that user use different entry points to mess up BentoBox's accounting.If the team added this feature to support token farming or trapped tokens, it would make sense to add onlyOwner
sweep function to do that; If it was mainly for interacting with other protocols, I suggest add a custom interface as a middle layer: So only allow the NFTPair
contract to call ICallee(callee).ourSpecialCall(data)
, and for each cool feature you want to support you add a new callee contract which works as a security proxy.
IMO arbitrary calls lead to a huge space of potential vulnerabilities (some of them might still be unknown), so i would suggest to completely remove the possibility of volnerability by replacing it with one of the solution above.
#0 - cryptolyndon
2022-05-13T05:54:36Z
Seen, thanks
🌟 Selected for report: BowTiedWardens
Also found by: 0x1f8b, 0xNazgul, 0xf15ers, 0xkatana, CertoraInc, Funen, GimelSec, Hawkeye, IllIllI, Kulk0, NoamYakov, Tadashi, Tomio, TrungOre, antonttc, catchup, defsec, delfin454000, fatherOfBlocks, gzeon, horsefacts, joestakey, kenta, oyc_109, pauliax, reassor, robee, samruna, simon135, slywaters, sorrynotsorry, z3s
44.2119 MIM - $44.21
_lend
when used in through requestAndBorrow
or takeCollateralAndLend
_lend
, it takes an parameter called accepted
and compare it with the state variable tokenLoanParams to make sure the borrower didn't front-run the tx. This is a good check, but in requestAndBorrow
and takeCollateralAndLend
, same parameters are passed in for _requestLoan
and _lend
, considering these are probably the most used function, it would be better to use a boolean call checkLoan to decide if we need this check or not. It will only be needed in lend
function. (or just move the check into a different internal function and call it before lend
)#0 - cryptolyndon
2022-05-13T06:07:05Z
Duplicate of #195