Platform: Code4rena
Start Date: 14/06/2022
Pot Size: $100,000 USDC
Total HM: 26
Participants: 59
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 9
Id: 133
League: ETH
Rank: 18/59
Findings: 9
Award: $1,719.86
🌟 Selected for report: 1
🚀 Solo Findings: 0
126.3383 USDC - $126.34
782.2807 CANTO - $126.34
updateBaseRate is marked public and can be called by any user to update the base rate as per their choice Attacker can simply call this function to change the base rate per year to incur more profits
function updateBaseRate(uint newBaseRatePerYear) public { // check the current block number uint blockNumber = block.number; uint deltaBlocks = blockNumber.sub(lastUpdateBlock); if (deltaBlocks > updateFrequency) { // pass in a base rate per year baseRatePerYear = newBaseRatePerYear; lastUpdateBlock = blockNumber; emit NewInterestParams(baseRatePerYear); } }
Add below check so that only Admin can call this function
require(msg.sender == admin, "only the admin may set the update frequency");
#0 - ecmendenhall
2022-06-21T22:12:24Z
#1 - tkkwon1998
2022-06-22T17:49:50Z
Duplicate of issue #22
🌟 Selected for report: Soosh
Also found by: 0x1f8b, Ruhum, TerrierLover, WatchPug, cccz, csanuragjain, hake, p4st13r4, zzzitron
126.3383 USDC - $126.34
782.2807 CANTO - $126.34
On calling AddProposal function with same propId , the older proposal will get overridden. This can become a problem. User can see a proposal and approve it. But before proposal is queue/executed, user can change it using same proposal id
If proposal with same id is already existing then AddProposal function should revert
#0 - tkkwon1998
2022-06-22T17:58:20Z
Duplicate of issue #26 . This issue only exists because anyone can add to the proposal store. As such, the root issue of this is issue 26.
1532.982 CANTO - $247.58
247.5766 USDC - $247.58
The queue function marks the transaction execution as true which is incorrect. newProposal.executed should not be set to true as this transaction could never be executed since state(proposalId) will not be equal to ProposalState.Queued, thus failing at execute function
Change GovernorBravoDelegate.sol#L63 to
newProposal.executed = false;
#0 - tkkwon1998
2022-06-22T17:57:14Z
Duplicate of issue #39
🌟 Selected for report: csanuragjain
1635.5547 CANTO - $264.14
264.1421 USDC - $264.14
It was observed that in repayBorrowFresh function, User is asked to send repayAmount instead of repayAmountFinal. This can lead to loss of user funds as user might be paying extra
User is making a repayment which eventually calls repayBorrowFresh function
Assuming repayAmount == type(uint).max, so repayAmountFinal becomes accountBorrowsPrev
This means User should only transfer in accountBorrowsPrev instead of repayAmount but that is not true. Contract is transferring repayAmount instead of repayAmountFinal as seen at CNote.sol#L129
uint actualRepayAmount = doTransferIn(payer, repayAmount);
Revise CNote.sol#L129 to below:
uint actualRepayAmount = doTransferIn(payer, repayAmountFinal);
#0 - GalloDaSballo
2022-08-07T23:26:29Z
The warden has showed how, due to an oversight, using type(uint).max
to signify a complete repayment will actually attempt to transfer 2^256-1 units of token.
While I think High severity would have been reasonable had the tokens gotten transferred, because what will actually happen is a revert, I think Medium Severity to be more appropriate.
Remediation requires using actualRepayAmount
or re-assigning the value of repayAmount
🌟 Selected for report: joestakey
Also found by: 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xf15ers, 0xmint, Bronicle, Dravee, Funen, JMukesh, Limbooo, MadWookie, Picodes, Ruhum, TerrierLover, TomJ, Tutturu, WatchPug, Waze, _Adam, asutorufos, c3phas, catchup, cccz, codexploder, cryptphi, csanuragjain, defsec, fatherOfBlocks, gzeon, hake, hansfriese, hyh, ignacio, k, nxrblsrpr, oyc_109, robee, sach1r0, saian, simon135, technicallyty, zzzitron
79.9481 USDC - $79.95
687.9945 CANTO - $111.11
Admin can set a very high value of update frequency which will make sure that updateBaseRate can be never be called. This way only Admin would be sole decider of base rate using _setBaseRatePerYear
Observe that Admin can set a very large block.number value for update frequency using _setUpdateFrequency function
Now updateBaseRate cannot be called since the interval set in step 1 is too large to be reached
Admin becomes sole decider of changing base rate whenever Admin wishes using _setBaseRatePerYear function
Add a max cap on updated frequency value
#0 - nivasan1
2022-06-23T20:52:49Z
This value is regulated by governance, as such, it is not necessary to regulate the update frequency value
#1 - GalloDaSballo
2022-08-12T00:45:29Z
I think the finding is valid
I also think the issue is the fact that the function updateBaseRate
is public
is a bigger severity, but I'm going to assume the function is admin only.
In that case, the value of updateFrequency
is a guarantee that interest rate won't change before that time.
I think the observation is correct, the value can be set to any crazy high value, however I don't see any major risk with that as the variable is public and the worst case is a guarantee that the rate will never change (which is not a bad thing necessarily)
For those reasons, am downgrading to QA