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

Failing to reset the allowance to zero before safeApprove

Summary

The StrategyOp.sol contract utilizes the safeApprove function from OpenZeppelin's SafeERC20 library for setting token allowances. However, the contract fails to reset allowances to 0 before setting a new approval value. This oversight can lead to reverts due to the strict requirements of safeApprove, breaking the functionality of key operations, such as updating the router in setRouter().

Vulnerability Details

The following functions in StrategyOp.sol use safeApprove to grant token approvals but do not reset the current allowance to 0 before setting a new one:

  • _initStrategy():

underlying.safeApprove(address(router), type(uint256).max);
  • setRouter(address _router):

underlying.safeApprove(router, type(uint256).max);

Because of the behavior of safeApprove If a non-zero allowance already exists, attempting to set a new allowance will revert.

Impact

Functional Breakage:

  • Functions relying on safeApprove will revert if called with an existing non-zero allowance. This can disrupt key contract operations, such as updating the router in setRouter().

  • Loss of Upgradability:
    The inability to update the router address without resetting allowances can make the contract inflexible and prone to operational failures.

  • Compatibility Issues:
    Some ERC20 tokens may behave non-standardly (e.g., tokens that don't return a bool), which safeApprove is designed to handle. However, the lack of zero-reset before re-approvals makes this compatibility moot, as reverts will still occur.

Severity: Medium

Likelihood: Low (only occurs when updating router or redeploying strategy).
Impact: Medium (breaks functionality and limits contract flexibility).

Tools Used

Solidity Metrics,
Foundry,
Manual Review,
AI

Recommendations

Modify setRouter and _initStrategy to reset allowances to zero before granting new approvals:

function setRouter(address _router) external onlyManagement {
router = _router;
uint256 allowance = underlying.allowance(address(this), router);
if (allowance < type(uint256).max) {
if (allowance > 0) {
underlying.safeApprove(router, 0); // Reset non-zero allowance
}
underlying.safeApprove(router, type(uint256).max);
}
}
function _initStrategy() internal {
router = 0xa062aE8A9c5e11aaA026fc2670B0D65cCc8B2858;
uint256 allowance = underlying.allowance(address(this), router);
if (allowance < type(uint256).max) {
if (allowance > 0) {
underlying.safeApprove(router, 0); // Reset non-zero allowance
}
underlying.safeApprove(router, type(uint256).max);
}
}
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.