Althea Liquid Infrastructure - atoko's results

Liquid Infrastructure.

General Information

Platform: Code4rena

Start Date: 13/02/2024

Pot Size: $24,500 USDC

Total HM: 5

Participants: 84

Period: 6 days

Judge: 0xA5DF

Id: 331

League: ETH

Althea

Findings Distribution

Researcher Performance

Rank: 43/84

Findings: 3

Award: $53.05

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L127

Vulnerability details

Impact

The following function is used to transfer tokens to an address to which proceeds to add the user to Holders array if they do not have any balance

 bool exists = (this.balanceOf(to) != 0);
        if (!exists) {
            holders.push(to);
        }

while it checks to ensure the user does not have any balances before pushing them to the array, the check is not sufficient

Proof of Concept

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        require(!LockedForDistribution, "distribution in progress");
        if (!(to == address(0))) {
            require(
                isApprovedHolder(to),
                "receiver not approved to hold the token"
            );
        }
        if (from == address(0) || to == address(0)) {
            _beforeMintOrBurn();
        }
        bool exists = (this.balanceOf(to) != 0);
        if (!exists) {
            holders.push(to);
        }
    }

lets assume that the function _beforeTokenTransfer() is successful and receiver address to is added to the holders array. Since there is no check to ensure that user in not already in the array, a malicious user could take advantage of this discrepancy. lets take a look at an example POC

1.Malicious user gets token and is added to the holders array. 2.He burns all the tokens and his balance is back to 0 3.The user then receives tokens multiple times from different senders, each time being added to the Holders array anew. 4.The distribute function is called it loops through the holders array and gives him rewards multiple times, since there is no check to prevent addresses from getting multiple rewards in one block. when this process is repeated multiple times the malicious user could benefit from getting so many rewards 5.Through this process, the malicious user unfairly receives multiple rewards, exploiting the lack of validation for existing holders.

Tools Used

manual review

Before adding an address to the Holders array, verify if the address is already present to prevent duplication.

Implement checks to ensure that rewards are not distributed to the same address multiple times in the same block or distribution cycle.

Assessed type

Token-Transfer

#0 - c4-pre-sort

2024-02-22T05:20:01Z

0xRobocop marked the issue as duplicate of #77

#1 - c4-judge

2024-03-04T13:22:24Z

0xA5DF marked the issue as satisfactory

Awards

20.1396 USDC - $20.14

Labels

bug
2 (Med Risk)
insufficient quality report
partial-25
duplicate-703

External Links

Lines of code

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L216

Vulnerability details

Impact

in the protocol a user can be disapproved by the owner using the disapproveHolder which removes them from the HolderAllowlist mapping. While this approach is okay the user will end up not receiving their rewards.

Proof of Concept

in the function

    function disapproveHolder(address holder) public onlyOwner {
        require(isApprovedHolder(holder), "holder not approved");
        HolderAllowlist[holder] = false;
    }

while distributing rewards the following function is also checked

  function approveHolder(address holder) public onlyOwner {
        require(!isApprovedHolder(holder), "holder already approved");
        HolderAllowlist[holder] = true;
    }

the approveHolder function makes sure that the user is in the HolderAllowlist

which is further checked by the distribute function before distributing the rewards

 if (isApprovedHolder(recipient)) {
                uint256[] memory receipts = new uint256[](
                    distributableERC20s.length
                );
                for (uint j = 0; j < distributableERC20s.length; j++) {
                    IERC20 toDistribute = IERC20(distributableERC20s[j]);
                    uint256 entitlement = erc20EntitlementPerUnit[j] *
                        this.balanceOf(recipient);
                    if (toDistribute.transfer(recipient, entitlement)) {
                        receipts[j] = entitlement;
                    }
                }

The check makes sure the user is in the HolderAllowlist before they can get rewards. this means that if a user was in the list and had accrued some rewards the rewards will be stuck and never get to him.

Tools Used

manual review

Implement a mechanism to distribute accrued rewards to disapproved users before they are removed from the HolderAllowlist mapping. This ensures that users receive the rewards they have earned even if they are later disapproved by the owner.

Assessed type

Other

#0 - c4-pre-sort

2024-02-22T05:25:43Z

0xRobocop marked the issue as insufficient quality report

#1 - c4-pre-sort

2024-02-22T05:25:45Z

0xRobocop marked the issue as primary issue

#2 - 0xRobocop

2024-02-22T05:25:49Z

Consider QA

#3 - c4-judge

2024-03-05T12:18:53Z

0xA5DF marked the issue as duplicate of #703

#4 - c4-judge

2024-03-05T12:19:00Z

0xA5DF marked the issue as partial-25

#5 - 0xA5DF

2024-03-05T12:19:55Z

Partial dupe of #703, would credit the dupes according to how much they've identified the impact

Awards

25.7286 USDC - $25.73

Labels

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

External Links

Lines of code

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L441

Vulnerability details

Impact

The function setDistributableERC20s enables the owner to add or remove ERC20 tokens from the list of distributable tokens. However, this could potentially overwrite the existing tokens in the system, leading to users lose rewards earned from the removed ERC20 tokens.

Proof of Concept

   function setDistributableERC20s(
        address[] memory _distributableERC20s
    ) public onlyOwner {
        distributableERC20s = _distributableERC20s;
    }

The code above will alter the existing distributableERC20s in case one is removed from the list and it has pending rewards the rewards could be lost.

Tools Used

manual review

Add a check to ensure that Before modifying the list of distributable ERC20 tokens, ensure that any pending distributions for the affected tokens are completed. This can prevent users from losing their rewards associated with the removed tokens.

Assessed type

Context

#0 - c4-pre-sort

2024-02-20T04:25:17Z

0xRobocop marked the issue as duplicate of #111

#1 - c4-pre-sort

2024-02-20T04:40:10Z

0xRobocop marked the issue as duplicate of #260

#2 - c4-judge

2024-03-04T15:20:59Z

0xA5DF marked the issue as satisfactory

#3 - c4-judge

2024-03-08T15:26:19Z

0xA5DF 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