The AlchemistAllocator calculates an adjusted cap by selecting the appropriate limit between absoluteCap, relativeCap, and daoTarget but fails to enforce it, allowing allocate and deallocate calls to bypass intended risk limits and pass unchecked amounts to the vault.
Vulnerability Details
Offer a detailed explanation of the vulnerability This issue affects both allocate and deallocate functions. Here's the full relevant code for each, highlighting the unused adjusted calculation: In the AlchemistAllocator.sol,
In allocate function:
functionallocate(addressadapter,uint256amount)external{require(msg.sender== admin || operators[msg.sender],"PD");bytes32 id =IMYTStrategy(adapter).adapterId();uint256 absoluteCap = vault.absoluteCap(id);uint256 relativeCap = vault.relativeCap(id);// FIXME get this from the StrategyClassificationProxy for the respective risk class uint256 daoTarget =type(uint256).max;uint256 adjusted = absoluteCap > relativeCap ? absoluteCap : relativeCap;if(msg.sender!= admin){// caller is operator adjusted = adjusted > daoTarget ? adjusted : daoTarget;}// pass the old allocation to the adapter bytesmemory oldAllocation =abi.encode(vault.allocation(id)); vault.allocate(adapter, oldAllocation, amount);}
In deallocate function:
The variables absoluteCap, relativeCap, and daoTarget are fetched to compute adjusted, which is meant to represent a safe limit for the amount being allocated or deallocated based on strategy caps and targets; however, adjusted is calculated but never used or compared against amount, so the vault receives the full amount without any limit enforcement.
Impact Details
Without enforcing adjusted against amount, the contract allows unlimited allocations or deallocations, bypassing risk limits and potentially exposing the vault to excessive funds in unsafe strategies.
Recommended Fix
Add a check like require(amount <= adjusted, "Exceeds cap"); in allocate.
For deallocate, check require(amount <= vault.allocation(id), "Exceeds current allocation");
Vault enforces its own relativeCap and reverts with RelativeCapExceeded()
Why This Proves the Vulnerability:
The allocator's logic determined that absoluteCap (200e) should be the governing limit, NOT relativeCap (50e). This is what the adjusted calculation represents - picking the maximum of the two caps.
If the allocator had enforced its adjusted calculation:
It would check: require(100 <= 200) PASS
The allocation would be allowed from the allocator's perspective
But since the allocator ignores adjusted:
It blindly passes 100 ether to the vault
The vault independently enforces BOTH caps (not just the max)
The vault rejects because 100 > 50 (relative cap)
This makes the entire cap selection logic dead code with no purpose, proving the bug report is valid and definitively proves the unused adjusted variable vulnerability!