Arcade.xyz - bin2chen's results

The first of its kind Web3 platform to enable liquid lending markets for NFTs.

General Information

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

Arcade.xyz

Findings Distribution

Researcher Performance

Rank: 7/60

Findings: 1

Award: $2,337.55

🌟 Selected for report: 1

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: bin2chen

Also found by: 0xWaitress, caventa, ladboy233

Labels

bug
2 (Med Risk)
primary issue
satisfactory
selected for report
sponsor confirmed
M-06

Awards

2337.5492 USDC - $2,337.55

External Links

Lines of code

https://github.com/code-423n4/2023-07-arcade/blob/f8ac4e7c4fdea559b73d9dd5606f618d4e6c73cd/contracts/ArcadeTreasury.sol#L391

Vulnerability details

Impact

direct use of IERC20(token).approve(spender, amount); causes the same spender allowances to be overridden by each other

Proof of Concept

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

Tools Used

    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);
    } 

Assessed type

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

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter