30598 - [SC - Low] Access Control Flaw in _burn Function Leads to ...

Submitted on May 1st 2024 at 19:08:15 UTC by @Limbooo for Boost | Alchemix

Report ID: #30598

Report type: Smart Contract

Report severity: Low

Target: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/VotingEscrow.sol

Impacts:

  • Contract fails to deliver promised returns, but doesn't lose value

  • Temporary freezing of NFTs

Description

Brief/Intro

The vulnerability in the VotingEscrow contract arises due to an access control flaw within the _burn function, which inappropriately handles approval resetting, requiring broader permissions than necessary. This flaw disrupts operations such as token merging and withdrawals, as transactions initiated by users who are only approved for specific token IDs (and not globally) revert unexpectedly. On mainnet, this could lead to operational disruptions, preventing users from consolidating voting power or accessing their funds post-lock period, thereby undermining user trust and the functionality of the contract. Such issues could significantly impact user engagement and the platform's overall reliability.

Vulnerability Details

Lines of Code

alchemix-v2-dao/src/VotingEscrow.sol #L1567[^1]

In VotingEscrow.sol contracts, there are multiple functions that allow whether the msg.sender is approved for the given token ID, is an operator of the owner, or is the owner of the token by utilizing _isApprovedOrOwner function.

However, two of these functions are in question in this report; merge and withdraw, since the _burn function is used.

The _burn function within the VotingEscrow contract is designed to remove tokens from circulation by clearing approvals and performing other state updates. However, due to the way access control is implemented, only the token owner or an entity approved for all user tokens can successfully execute this function without causing a revert. This is because the function internally calls approve(address(0), _tokenId), which checks for broader permissions than those granted to entities approved for a single token.

Impact Details

This results in operational disruptions for users who are legitimately authorized to perform actions (like merge and withdraw) that rely on _burn. They may encounter transaction reverts, leading to:

  • Inability to merge tokens for voting power consolidation or management.

  • Failed attempts to withdraw tokens post-lock period, leading to user dissatisfaction and potential disruption in planned economic activities within the platform.

  • Consider refactoring approval logic in _burn, Modify the internal logic of the _burn function to handle cases where the caller is only approved for the specific token ID being burned. This could involve bypassing the approval reset or adjusting the approval check to recognize and allow this scenario.

  • Consider standardizing the approval reset process to use _clearApproval, especially in contexts where specific token approval is sufficient. This would align the behavior across different contract functions and improve the reliability of operations involving token transfers, burns, or modifications.

References

  • https://github.com/alchemix-finance/alchemix-v2-dao/blob/f1007439ad3a32e412468c4c42f62f676822dc1f/src/VotingEscrow.sol#L1567

  • https://github.com/alchemix-finance/alchemix-v2-dao/blob/f1007439ad3a32e412468c4c42f62f676822dc1f/src/VotingEscrow.sol#L501C1-L514C6

  • https://github.com/alchemix-finance/alchemix-v2-dao/blob/f1007439ad3a32e412468c4c42f62f676822dc1f/src/VotingEscrow.sol#L912C5-L919C6

Proof of Concept

Consider a scenario where a user has received specific approval for token ID 123 to facilitate a token merge or withdrawal. Under the current implementation, if this user attempts to initiate these actions, the transaction will revert during the _burn call due to the internal approve function not recognizing their limited approval as sufficient.

This scenario can be replicated in a test environment to demonstrate the failure mechanism and its impact on contract usability.

Test Case (Foundry)

Test Output

Last updated

Was this helpful?