Platform: Code4rena
Start Date: 21/07/2023
Pot Size: $90,500 USDC
Total HM: 8
Participants: 60
Period: 7 days
Judge: 0xean
Total Solo HM: 2
Id: 264
League: ETH
Rank: 7/60
Findings: 1
Award: $2,337.55
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: bin2chen
Also found by: 0xWaitress, caventa, ladboy233
2337.5492 USDC - $2,337.55
direct use of IERC20(token).approve(spender, amount);
causes the same spender
allowances to be overridden by each other
In the gscApprove()
method it is possible to give spender
a certain allowance
The code is as follows:
function gscApprove( address token, address spender, uint256 amount ) external onlyRole(GSC_CORE_VOTING_ROLE) nonReentrant { if (spender == address(0)) revert T_ZeroAddress("spender"); if (amount == 0) revert T_ZeroAmount(); // Will underflow if amount is greater than remaining allowance @> gscAllowance[token] -= amount; _approve(token, spender, amount, spendThresholds[token].small); } function _approve(address token, address spender, uint256 amount, uint256 limit) internal { // check that after processing this we will not have spent more than the block limit uint256 spentThisBlock = blockExpenditure[block.number]; if (amount + spentThisBlock > limit) revert T_BlockSpendLimit(); blockExpenditure[block.number] = amount + spentThisBlock; // approve tokens @> IERC20(token).approve(spender, amount); emit TreasuryApproval(token, spender, amount); }
From the above code we can see that when executed gscApprove
consumes gscAllowance[]
and ultimately uses IERC20(token).approve();
to give the spender
allowance
Since the direct use is IERC20.approve(spender, amount)
, the amount of the allowance is overwritten, whichever comes last
In the other methods approveSmallSpend
,approveMediumSpend
,approveLargeSpend
also use IERC20(token).approve();
, which causes them to override each other if targeting the same spender
.
Even if there is a malicious GSC_CORE_VOTING_ROLE
, it is possible to execute gscApprove(amount=1 wei)
after approveLargeSpend()
to reset to an allowance of only 1 wei
.
The recommendation is to use accumulation to avoid, intentionally or unintentionally, overwriting each other
function _approve(address token, address spender, uint256 amount, uint256 limit) internal { // check that after processing this we will not have spent more than the block limit uint256 spentThisBlock = blockExpenditure[block.number]; if (amount + spentThisBlock > limit) revert T_BlockSpendLimit(); blockExpenditure[block.number] = amount + spentThisBlock; // approve tokens - IERC20(token).approve(spender, amount); + uint256 old = IERC20(token).allowance(address(this),spender); + IERC20(token).approve(spender, old + amount); emit TreasuryApproval(token, spender, amount); }
Context
#0 - c4-pre-sort
2023-07-29T13:41:48Z
141345 marked the issue as primary issue
#1 - 141345
2023-07-29T14:12:05Z
https://github.com/code-423n4/2023-07-arcade-findings/issues/58 talks about the issue with internal accounting of gscAllowance. Another aspect of the issue.
And this report shows some unexpected result due to external erc20 allowance overwrite.
#2 - c4-sponsor
2023-08-02T20:00:36Z
PowVT marked the issue as sponsor confirmed
#3 - c4-judge
2023-08-10T21:45:56Z
0xean marked the issue as satisfactory
#4 - c4-judge
2023-08-12T14:00:59Z
0xean marked the issue as selected for report
#5 - Nabeel-javaid
2023-08-15T05:36:42Z
Doesn't it falls under the admin mistake, admin would be aware and can change these to desired values anytime.
#6 - 0xean
2023-08-15T17:47:00Z
Doesn't it falls under the admin mistake, admin would be aware and can change these to desired values anytime.
I don't believe this should be view as input sanitization as the core functionality is written in a way that has unexpected consequences that could affect the functionality of the protocol. I can see arguing for QA, I welcome more comments from other wardens or sponsor ( @c4-sponsor )
#7 - nevillehuang
2023-08-15T18:04:42Z
Doesn't it falls under the admin mistake, admin would be aware and can change these to desired values anytime.
I don't believe this should be view as input sanitization as the core functionality is written in a way that has unexpected consequences that could affect the functionality of the protocol. I can see arguing for QA, I welcome more comments from other wardens or sponsor ( @c4-sponsor )
Correct me if im wrong, I think it is intended for allowance to be overriden for spender when it is decreased, given changing of approval needs to go through a GSC proposal
But since this report also highlights the potential inability to reduce allowance due to underflow in the gscAllowance mapping, it should be duplicated with #58
Again correct me if im wrong, If the above reasoning is correct, #55, #146 and #535 should be invalidated since they do not mention the possible DoS when decreasing allowance.
#8 - jingyi2811
2023-08-16T09:04:34Z
Hi Oxean. I don't think the item on qa report 506 is the duplicate of this issue. Tqs