Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swap functionality to sell rewards is too permissive and could cause accidental or intentional loss of value #54

Open
c4-submissions opened this issue Sep 27, 2023 · 3 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working M-02 primary issue Highest quality submission among a set of duplicates selected for report This submission will be included/highlighted in the audit report sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")

Comments

@c4-submissions
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2023-09-asymmetry/blob/main/contracts/strategies/votium/VotiumStrategyCore.sol#L272-L305

Vulnerability details

Summary

While the intention is to use the 0x protocol to sell rewards, the implementation doesn't provide any basic guarantee this will correctly happen and grants the rewarder arbitrary control over the tokens held by the strategy.

Impact

Rewards earned in the VotingStrategy contract are exchanged for ETH and deposited back into the protocol. As indicated by the documentation, the intention is to swap these rewards for ETH using the 0x protocol:

Votium rewards are claimed with claimRewards() using merkle proofs published by votium every 2 weeks. applyRewards() sells rewards on 0x and deposits them back into afEth (and ultimately back into the safEth & votium strategies), making the afEth price go up.

However, the implementation of applyRewards() shallowly executes a series of calls to arbitrary targets:

https://github.com/code-423n4/2023-09-asymmetry/blob/main/contracts/strategies/votium/VotiumStrategyCore.sol#L272-L305

272:     function applyRewards(SwapData[] calldata _swapsData) public onlyRewarder {
273:         uint256 ethBalanceBefore = address(this).balance;
274:         for (uint256 i = 0; i < _swapsData.length; i++) {
275:             // Some tokens do not allow approval if allowance already exists
276:             uint256 allowance = IERC20(_swapsData[i].sellToken).allowance(
277:                 address(this),
278:                 address(_swapsData[i].spender)
279:             );
280:             if (allowance != type(uint256).max) {
281:                 if (allowance > 0) {
282:                     IERC20(_swapsData[i].sellToken).approve(
283:                         address(_swapsData[i].spender),
284:                         0
285:                     );
286:                 }
287:                 IERC20(_swapsData[i].sellToken).approve(
288:                     address(_swapsData[i].spender),
289:                     type(uint256).max
290:                 );
291:             }
292:             (bool success, ) = _swapsData[i].swapTarget.call(
293:                 _swapsData[i].swapCallData
294:             );
295:             if (!success) {
296:                 emit FailedToSell(_swapsData[i].sellToken);
297:             }
298:         }
299:         uint256 ethBalanceAfter = address(this).balance;
300:         uint256 ethReceived = ethBalanceAfter - ethBalanceBefore;
301: 
302:         if (address(manager) != address(0))
303:             IAfEth(manager).depositRewards{value: ethReceived}(ethReceived);
304:         else depositRewards(ethReceived);
305:     }

This not only fails to provide any guarantee that 0x will be used (and that it will be used correctly), but grants a lot of power to the rewarder which can be used accidentally or purposely to negatively impact the protocol. The rewarded role can grant any token approval to any spender and execute arbitrary calls on behalf of the VotingStrategy.

Recommendation

Provide better guarantees in the implementation of applyRewards() that 0x will be used to swap rewards, to ensure a more transparent and less error prone solution.

  • Instead of granting arbitrary allowance to any spender, set this to the 0x entrypoint.
  • Change arbitrary calls to the 0x protocol entrypoint.
  • Data sent to the 0x contract could also be validated, for example to ensure the output token is ETH.

Assessed type

Other

@c4-submissions c4-submissions added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Sep 27, 2023
c4-submissions added a commit that referenced this issue Sep 27, 2023
@c4-judge c4-judge added the primary issue Highest quality submission among a set of duplicates label Oct 3, 2023
@c4-judge
Copy link
Contributor

c4-judge commented Oct 3, 2023

0xleastwood marked the issue as primary issue

@c4-judge c4-judge added the selected for report This submission will be included/highlighted in the audit report label Oct 4, 2023
@c4-judge
Copy link
Contributor

c4-judge commented Oct 4, 2023

0xleastwood marked the issue as selected for report

@c4-sponsor c4-sponsor added the sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") label Oct 4, 2023
@c4-sponsor
Copy link

elmutt (sponsor) confirmed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working M-02 primary issue Highest quality submission among a set of duplicates selected for report This submission will be included/highlighted in the audit report sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Projects
None yet
Development

No branches or pull requests

4 participants