Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Approval Without Validation

Summary

https://github.com/Cyfrin/2025-01-zaros-part-2/blob/39e33b2f6b3890573bb1affc41a7e520277ceb2c/src/zlp/ZlpVault.sol#L59

The ZlpVault contract contains a potential vulnerability where the approval of assets for the MarketMakingEngine is done without proper validation or safeguards. Specifically, the contract approves an unlimited amount of the asset token (type(uint256).max) for the MarketMakingEngine without checking whether this is necessary or whether it could be abused. This could lead to an attacker gaining the ability to transfer more tokens than expected.

Vulnerability Details

function initialize(
address marketMakingEngine,
uint8 decimalsOffset,
address owner,
IERC20 asset_,
uint128 vaultId
) external initializer {
__Ownable_init(owner);
__ERC4626_init(asset_);
ZlpVaultStorage storage zlpVaultStorage = _getZlpVaultStorage();
zlpVaultStorage.marketMakingEngine = marketMakingEngine;
zlpVaultStorage.decimalsOffset = decimalsOffset;
zlpVaultStorage.vaultId = vaultId;
IERC20(asset_).approve(marketMakingEngine, type(uint256).max); // Unlimited approval
}

The IERC20(asset_).approve(marketMakingEngine, type(uint256).max) function call approves an unlimited amount of tokens for the MarketMakingEngine.

Approval without validation: This approval is done without checking the exact needs of the MarketMakingEngine. If the MarketMakingEngine needs only a limited amount of tokens, this could expose the vault to unnecessary risks, as the contract grants excessive permissions.

This could be exploited by a malicious actor who gains control of the MarketMakingEngine, allowing them to drain tokens from the vault.

Exploitation Scenario:

An attacker who gains control over the MarketMakingEngine could call functions that transfer tokens from the vault without restrictions, draining the vault's assets. This risk is especially critical if the vault holds significant user funds.

Impact

Unnecessary Exposure: The contract gives full approval for an unlimited amount of tokens, which could lead to the MarketMakingEngine transferring an excessive amount of tokens.

Asset Drainage: A malicious actor controlling MarketMakingEngine could steal tokens by transferring more than expected.

Loss of Control: If the MarketMakingEngine is compromised, the vault owner has limited ability to revert excessive approvals, leading to permanent loss of funds.

Tools Used

Manual Review

Recommendations

Limit Asset Approval

Instead of approving an unlimited amount of tokens, approve a fixed amount based on the actual needs of the MarketMakingEngine. A better approach would be to dynamically calculate the amount of tokens needed and approve only that amount:

function initialize(
address marketMakingEngine,
uint8 decimalsOffset,
address owner,
IERC20 asset_,
uint128 vaultId
) external initializer {
__Ownable_init(owner);
__ERC4626_init(asset_);
ZlpVaultStorage storage zlpVaultStorage = _getZlpVaultStorage();
zlpVaultStorage.marketMakingEngine = marketMakingEngine;
zlpVaultStorage.decimalsOffset = decimalsOffset;
zlpVaultStorage.vaultId = vaultId;
// Approve the necessary amount based on actual usage (for example, set a reasonable cap)
uint256 approvalAmount = calculateRequiredApprovalAmount(marketMakingEngine);
IERC20(asset_).approve(marketMakingEngine, approvalAmount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
5 months ago
inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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