Redacted Cartel contest - cccz's results

Boosted GMX assets from your favorite liquid token wrapper, Pirex - brought to you by Redacted Cartel.

General Information

Platform: Code4rena

Start Date: 21/11/2022

Pot Size: $90,500 USDC

Total HM: 18

Participants: 101

Period: 7 days

Judge: Picodes

Total Solo HM: 4

Id: 183

League: ETH

Redacted Cartel

Findings Distribution

Researcher Performance

Rank: 26/101

Findings: 5

Award: $368.68

🌟 Selected for report: 1

🚀 Solo Findings: 0

Findings Information

Labels

bug
3 (High Risk)
partial-25
upgraded by judge
duplicate-178

Awards

41.6303 USDC - $41.63

External Links

Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L199-L217

Vulnerability details

Impact

When calling AutoPx*.previewWithdraw in AutoPx*.withdraw, the comment says "No need to check for rounding error, previewWithdraw rounds up".

    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public override returns (uint256 shares) {
        // Compound rewards and ensure they are properly accounted for prior to withdrawal calculation
        compound(poolFee, 1, 0, true);

        shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up.

But only PirexERC4626.previewWithdraw rounds up. AutoPx*.previewWithdraw overrides PirexERC4626.previewWithdraw, but does not round up.

    function previewWithdraw(uint256 assets)
        public
        view
        override
        returns (uint256)
    {
        // Calculate shares based on the specified assets' proportion of the pool
        uint256 shares = convertToShares(assets);

        // Save 1 SLOAD
        uint256 _totalSupply = totalSupply;

        // Factor in additional shares to fulfill withdrawal if user is not the last to withdraw
        return
            (_totalSupply == 0 || _totalSupply - shares == 0)
                ? shares
                : (shares * FEE_DENOMINATOR) /
                    (FEE_DENOMINATOR - withdrawalPenalty);
    }
...
    function convertToShares(uint256 assets)
        public
        view
        virtual
        returns (uint256)
    {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

This breaks the developer's intention and does not comply with the EIP-4626 specification

Proof of Concept

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L199-L217 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGlp.sol#L177-L195 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L99-L105 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L315-L323

Tools Used

None

Call PirexERC4626.previewWithdraw instead of convertToShares in AutoPx*.previewWithdraw

    function previewWithdraw(uint256 assets)
        public
        view
        override
        returns (uint256)
    {
        // Calculate shares based on the specified assets' proportion of the pool
-        uint256 shares = convertToShares(assets);
+       uint256 shares = PirexERC4626.previewWithdraw(assets);

#0 - c4-judge

2022-12-04T13:01:37Z

Picodes marked the issue as duplicate of #264

#1 - c4-judge

2022-12-04T13:02:12Z

Picodes marked the issue as partial-25

#2 - Picodes

2022-12-04T13:02:25Z

No impact described aside from the non compliance with the EIP

#3 - c4-judge

2023-01-01T11:34:42Z

Picodes changed the severity to 3 (High Risk)

#4 - C4-Staff

2023-01-10T21:57:30Z

JeeberC4 marked the issue as duplicate of #264

#5 - liveactionllama

2023-01-11T18:44:06Z

Duplicate of #178

Awards

25.3241 USDC - $25.32

Labels

bug
3 (High Risk)
satisfactory
upgraded by judge
duplicate-275

External Links

Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L370-L403

Vulnerability details

Impact

A well known attack vector for almost all shares based liquidity pool contracts, where an early user can manipulate the price per share and profit from late users' deposits because of the precision loss caused by the rather large value of price per share.

A malicious early user can deposit() with 1 wei of pxGMX as the first depositor of the apxGMX, and get 1 wei of shares.

Then the attacker can send 10000e18 - 1 of pxGMX and inflate the price per share from 1.0000 to an extreme value of 1.0000e22 ( from (1 + 10000e18 - 1) / 1) .

As a result, the future user who deposits 19999e18 will only receive 1 wei (from 19999e18 * 1 / 10000e18) of shares token.

They will immediately lose 9999e18 or half of their deposits if they redeem() right after the deposit().

Proof of Concept

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L60-L78 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L164-L166 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L339-L362 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L167-L176

Tools Used

None

Consider requiring a minimal amount of share tokens to be minted for the first minter, and send a part of the initial mints as a reserve to the DAO so that the pricePerShare can be more resistant to manipulation.

#0 - c4-judge

2022-12-04T13:18:19Z

Picodes marked the issue as duplicate of #407

#1 - c4-judge

2023-01-01T11:10:04Z

Picodes marked the issue as satisfactory

#2 - c4-judge

2023-01-01T11:36:31Z

Picodes changed the severity to 3 (High Risk)

#3 - C4-Staff

2023-01-10T21:54:30Z

JeeberC4 marked the issue as duplicate of #275

Findings Information

🌟 Selected for report: cccz

Also found by: Englave, Jeiwan, aphak5010, hansfriese, immeas, rbserver, xiaoming90

Labels

bug
2 (Med Risk)
disagree with severity
primary issue
satisfactory
selected for report
M-03

Awards

213.8538 USDC - $213.85

External Links

Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L242-L278

Vulnerability details

Impact

AutoPxGmx.compound allows anyone to call to compound the reward and get the incentive. However, AutoPxGmx.compound calls SWAP_ROUTER.exactInputSingle with some of the parameters provided by the caller, which allows the user to perform a sandwich attack for profit. For example, a malicious user could provide the fee parameter to make the token swap occur in a small liquid pool, and could make the amountOutMinimum parameter 1 to make the token swap accept a large slippage, thus making it easier to perform a sandwich attack.

Proof of Concept

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L242-L278

Tools Used

None

Consider using poolFee as the fee and using an onchain price oracle to calculate the amountOutMinimum

#0 - c4-judge

2022-12-04T12:56:41Z

Picodes marked the issue as duplicate of #391

#1 - c4-judge

2022-12-05T10:31:09Z

Picodes marked the issue as not a duplicate

#2 - c4-judge

2022-12-05T10:31:42Z

Picodes marked the issue as primary issue

#3 - c4-judge

2022-12-05T10:33:23Z

Picodes marked the issue as selected for report

#4 - Picodes

2022-12-05T10:34:14Z

Flagging as best as the warden identifies that the main risk is not the possibility to increase fees but the fact that some of the pools will be highly illiquid

#5 - c4-sponsor

2022-12-08T05:09:31Z

drahrealm marked the issue as disagree with severity

#7 - Picodes

2022-12-30T21:01:52Z

It's very likely that this attack is profitable as most of the time only 1 or 2 pools have decent liquidity, so medium severity is appropriate

#8 - c4-judge

2022-12-30T21:04:44Z

Picodes marked the issue as satisfactory

Awards

15.9293 USDC - $15.93

Labels

bug
2 (Med Risk)
satisfactory
duplicate-137

External Links

Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L242-L278

Vulnerability details

Impact

amountOutMinimum is 1 when compound() is called in some functions of the AutoPxGmx contract, and will be used as the amountOutMinimum parameter when calling SWAP_ROUTER.exactInputSingle

        compound(poolFee, 1, 0, true);

According to the https://docs.uniswap.org/contracts/v3/guides/swaps/single-swaps description, the amountOutMinimum should be calculated using the Uniswap SDK or the onchain price oracle. Simply setting it to 1 may result in losses due to improper slippage control.

Proof of Concept

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L242-L278 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L321-L322 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L345-L346 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L227-L228

Tools Used

None

Consider using the Uniswap SDK or the onchain price oracle to calculate the amountOutMinimum

#0 - c4-judge

2022-12-04T00:22:33Z

Picodes marked the issue as duplicate of #183

#1 - c4-judge

2022-12-30T20:53:41Z

Picodes marked the issue as duplicate of #185

#2 - c4-judge

2023-01-01T11:10:23Z

Picodes marked the issue as satisfactory

#3 - C4-Staff

2023-01-10T22:10:37Z

JeeberC4 marked the issue as duplicate of #137

Findings Information

🌟 Selected for report: xiaoming90

Also found by: 0x52, 8olidity, aphak5010, bin2chen, cccz, hansfriese, hihen, joestakey, ladboy233, rvierdiiev, unforgiven

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
duplicate-182

Awards

71.9536 USDC - $71.95

External Links

Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L152-L158

Vulnerability details

Impact

In the constructor of AutoPx*, when setting the platform, the platform is approved to use the contract's gmx or gmxBaseReward tokens in order to perform the token swap in the compound function.

        platform = _platform;
        rewardsModule = _rewardsModule;

        // Approve the Uniswap V3 router to manage our base reward (inbound swap token)
        gmxBaseReward.safeApprove(address(SWAP_ROUTER), type(uint256).max);
        gmx.safeApprove(_platform, type(uint256).max);

However, when the platform is updated in the setPlatform function, the new platform is not approved to use the tokens in the contract. This causes the compound function to fail when the platform is updated because the platform is not approved to use the tokens.

    function setPlatform(address _platform) external onlyOwner {
        if (_platform == address(0)) revert ZeroAddress();

        platform = _platform;

        emit PlatformUpdated(_platform);
    }

Proof of Concept

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L152-L158 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L92-L97 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGlp.sol#L130-L136 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGlp.sol#L83-L87

Tools Used

None

Change to

    function setPlatform(address _platform) external onlyOwner {
        if (_platform == address(0)) revert ZeroAddress();
+     gmx.safeApprove(platform, 0);
        platform = _platform;
+     gmx.safeApprove(_platform, type(uint256).max);
        emit PlatformUpdated(_platform);
    }
...
    function setPlatform(address _platform) external onlyOwner {
        if (_platform == address(0)) revert ZeroAddress();
+     gmxBaseReward.safeApprove(platform, 0);
        platform = _platform;
+     gmxBaseReward.safeApprove(_platform, type(uint256).max);
        emit PlatformUpdated(_platform);
    }

#0 - c4-judge

2022-12-04T13:18:37Z

Picodes marked the issue as duplicate of #182

#1 - c4-judge

2023-01-01T11:09:23Z

Picodes marked the issue as satisfactory

#2 - c4-judge

2023-01-01T11:29:18Z

Picodes changed the severity to 3 (High Risk)

#3 - c4-judge

2023-01-01T11:32:53Z

Picodes changed the severity to 2 (Med Risk)

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