DeFiFoundrySolidity
16,653 OP
View results
Submission Details
Severity: low
Valid

Infinite Token Approvals Without Revocation in Router Management

Summary

The strategy contracts (StrategyOp.sol, StrategyArb.sol, and StrategyMainnet.sol) implement a setRouter function that grants infinite token approvals to new routers without revoking approvals from previously approved routers. This could lead to security vulnerabilities if a previously approved router becomes compromised.

Vulnerability Details

When the management role calls setRouter to update the router address, the function grants an unlimited approval (type(uint256).max) to the new router without first revoking approvals from the old router address.

Code Snippet

function setRouter(address _router) external onlyManagement {
router = _router;
underlying.safeApprove(router, type(uint256).max);
}

The vulnerability exists in:

  • StrategyOp.sol

  • StrategyArb.sol

  • StrategyMainnet.sol

Impact

Severity: High

If a previously approved router contract becomes compromised (through upgrades, vulnerabilities, or malicious actions), the attacker could:

  1. Drain all underlying tokens up to the infinite approval amount

  2. Front-run or manipulate swaps

  3. Execute unauthorized token transfers

  4. Exploit the approval across multiple transactions

The impact is heightened because:

  • Approvals are for the maximum possible amount (type(uint256).max)

  • Multiple routers can have simultaneous infinite approvals

  • Attack could be executed at any time after router change

  • Recovery requires management intervention

Tools Used

Manual code review

Recommendations

Implement proper approval revocation in the setRouter function:

function setRouter(address _router) external onlyManagement {
require(_router != address(0), "Invalid router address");
// Revoke approval from old router if it exists
if (router != address(0)) {
underlying.safeApprove(router, 0);
}
// Update router and set new approval
router = _router;
underlying.safeApprove(_router, type(uint256).max);
emit RouterUpdated(_router);
}

Additional Recommendations

  1. Consider using incremental approvals instead of infinite approvals

  2. Add events for approval changes

  3. Implement a maximum approval amount configuration

  4. Add emergency approval revocation functionality

References

Test Cases

Added test cases should include:

function testRouterApprovalRevocation() public {
address newRouter = makeAddr("newRouter");
address oldRouter = strategy.router();
// Check initial approval
assertEq(underlying.allowance(address(strategy), oldRouter), type(uint256).max);
// Set new router
vm.prank(management);
strategy.setRouter(newRouter);
// Verify old approval is revoked
assertEq(underlying.allowance(address(strategy), oldRouter), 0);
// Verify new approval is set
assertEq(underlying.allowance(address(strategy), newRouter), type(uint256).max);
}

Mitigation Status

Pending implementation

Proof of Concept

Prerequisites

  • Management role access

  • Multiple router changes

  • Underlying token balance

Steps to Reproduce

  1. Deploy strategy with Router A

  2. Change router to Router B using setRouter

  3. Verify Router A still has infinite approval

  4. Using Router A account, attempt token transfer

  5. Observe successful unauthorized transfer

Updates

Appeal created

inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Old router approval is not revoked after an update

inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Old router approval is not revoked after an update

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.