FEI and TRIBE Redemption contest - hyh's results

A new DeFi primitive that allows any token to become productive and provide FEI liquidity at no cost to the markets that need it most.

General Information

Platform: Code4rena

Start Date: 09/09/2022

Pot Size: $42,000 USDC

Total HM: 2

Participants: 101

Period: 3 days

Judge: hickuphh3

Total Solo HM: 2

Id: 161

League: ETH

Tribe

Findings Distribution

Researcher Performance

Rank: 18/101

Findings: 1

Award: $34.50

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Lines of code

https://github.com/code-423n4/2022-09-tribe/blob/769b0586b4975270b669d7d1581aa5672d6999d5/contracts/shutdown/fuse/RariMerkleRedeemer.sol#L88-L97

Vulnerability details

User can rewrite the signature stored any number of times.

That's a violation of the desired system logic with no immediate loss of funds, so placing severity to be medium.

Proof of Concept

signAndClaim() don't control the signing status, so it can be run multiple times:

https://github.com/code-423n4/2022-09-tribe/blob/769b0586b4975270b669d7d1581aa5672d6999d5/contracts/shutdown/fuse/RariMerkleRedeemer.sol#L88-L97

    function signAndClaim(
        bytes calldata signature,
        address[] calldata cTokens,
        uint256[] calldata amounts,
        bytes32[][] calldata merkleProofs
    ) external override nonReentrant {
        // both sign and claim/multiclaim will revert on invalid signatures/proofs
        _sign(signature);
        _multiClaim(cTokens, amounts, merkleProofs);
    }

I.e. a user can rerun signAndClaim many times for example with empty cTokens and amounts arrays as _multiClaim() will be a noop in this case:

https://github.com/code-423n4/2022-09-tribe/blob/769b0586b4975270b669d7d1581aa5672d6999d5/contracts/shutdown/fuse/RariMerkleRedeemer.sol#L183-L198

    // User provides the cTokens & the amounts they should get, and it is verified against the merkle root for that cToken (for each cToken provided)
    // Should set the user's claim amount in the claims mapping for each cToken provided
    function _multiClaim(
        address[] calldata _cTokens,
        uint256[] calldata _amounts,
        bytes32[][] calldata _merkleProofs
    ) internal virtual {
        require(_cTokens.length == _amounts.length, "Number of cTokens and amounts must match");
        require(_cTokens.length == _merkleProofs.length, "Number of cTokens and merkle proofs must match");

        for (uint256 i = 0; i < _cTokens.length; i++) {
            _claim(_cTokens[i], _amounts[i], _merkleProofs[i]);
        }

        // no events needed here, they happen in _claim
    }

Consider adding the hasNotSigned modifier:

https://github.com/code-423n4/2022-09-tribe/blob/769b0586b4975270b669d7d1581aa5672d6999d5/contracts/shutdown/fuse/RariMerkleRedeemer.sol#L88-L97

    function signAndClaim(
        bytes calldata signature,
        address[] calldata cTokens,
        uint256[] calldata amounts,
        bytes32[][] calldata merkleProofs
-   ) external override nonReentrant {
+   ) external override hasNotSigned nonReentrant {
        // both sign and claim/multiclaim will revert on invalid signatures/proofs
        _sign(signature);
        _multiClaim(cTokens, amounts, merkleProofs);
    }

This way the behavior will be aligned with all other helper functions

#0 - kryptoklob

2022-09-13T06:55:33Z

This is low, as there are only two possible signatures that a user can provide, and both will still be valid, and it does not affect contract state or normal operation otherwise.

#1 - HickupHH3

2022-09-26T03:15:36Z

Agree with wardens that it is inconsistent behaviour, but I agree that the severity is low because there isn't an adverse impact apart from deviant behaviour and multiple emissions of the Signed() event.

#2 - HickupHH3

2022-09-26T03:16:31Z

warden's primary QA

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