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

Risk of Lifetime Approval Without Reset on Router Change

Issue:

The underlying.safeApprove(router, type(uint256).max) call in both _initStrategy and setRouter grants unlimited token allowance to the current router. However, the existing approval is not reset to zero before setting a new router. If the previous router is compromised, it retains the ability to transfer unlimited funds, even after the router is updated.

Impact:

High. Why?

  1. Unlimited Fund Access by a Compromised Router:

    A malicious or compromised router can drain the underlying tokens using the retained approval.

  2. Lack of Control Over Token Transfers:

    The contract cannot prevent misuse of allowances granted to previously approved routers.

  3. Extended Attack Surface:

    Multiple routers with type(uint256).max approvals significantly increase the protocol's vulnerability.


Evidence from Code:

setRouter Function:

function setRouter(address _router) external onlyManagement {
router = _router;
underlying.safeApprove(router, type(uint256).max); // No reset of previous approval
}

Potential Attack Scenario:

  1. Router Compromise Before Update:

    A malicious actor gains control of the current router.

  2. Approval Retention:

    The router retains its type(uint256).max allowance even after setRouter is called to update the router.

  3. Fund Drain:

    The malicious router transfers all underlying tokens using the retained unlimited allowance.

  4. Exploit Execution:

    The attacker repeatedly drains the strategy’s tokens until the protocol identifies and revokes the allowance manually.


Mitigation Steps

1. Reset Allowances Before Router Change:

Revoke existing approvals by setting them to zero before updating the router.

function setRouter(address _router) external onlyManagement {
// Revoke existing approval
underlying.safeApprove(router, 0);
// Set the new router and re-approve
router = _router;
underlying.safeApprove(router, type(uint256).max);
}

2. Implement Timelock for Router Changes:

Introduce a timelock mechanism for router updates to allow for auditing and review before execution.

uint256 public routerChangeTimelock;
address public pendingRouter;
function proposeRouterChange(address _newRouter) external onlyManagement {
pendingRouter = _newRouter;
routerChangeTimelock = block.timestamp + 1 days;
}
function executeRouterChange() external onlyManagement {
require(block.timestamp >= routerChangeTimelock, "Timelock not passed");
underlying.safeApprove(router, 0);
router = pendingRouter;
underlying.safeApprove(router, type(uint256).max);
pendingRouter = address(0);
}

3. Audit and Whitelist Routers:

Maintain a whitelist of trusted routers and enforce validation before updates.

mapping(address => bool) public trustedRouters;
function addTrustedRouter(address _router) external onlyOwner {
trustedRouters[_router] = true;
}
function setRouter(address _router) external onlyManagement {
require(trustedRouters[_router], "Router not trusted");
underlying.safeApprove(router, 0);
router = _router;
underlying.safeApprove(router, type(uint256).max);
}

Proof of Concept (PoC)

  1. Exploit Scenario:

    • The attacker compromises the current router and exploits its unlimited allowance after setRouter updates to a new router.

  2. Exploit Implementation:

    pragma solidity ^0.8.18;
    contract MaliciousRouter {
    IERC20 public token;
    constructor(address _token) {
    token = IERC20(_token);
    }
    function exploit(address strategy) external {
    uint256 allowance = token.allowance(strategy, address(this));
    require(allowance > 0, "No allowance");
    token.transferFrom(strategy, msg.sender, allowance); // Drain tokens
    }
    }
  3. Exploit Execution:

    • Deploy MaliciousRouter with the address of the underlying token.

    • Call exploit after observing that the router has been updated without resetting allowances.

Updates

Appeal created

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

Old router approval is not revoked after an update

inallhonesty Lead Judge 8 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.