The Router.listAnchor function can be called by anyone and tokens can be added.
The only check is that require(iPOOLS(POOLS).isAnchor(token)); but this can easily be set by calling Pools.addLiquidity(VADER, token, _) once even without actually sending any tokens to the contract.
This makes it an essentially useless check.
This only works initially as long as the anchorLimit has not been reached yet.
However, the replaceAnchor can be used in the same way and flash loans can be used to get around the liquidity restrictions and push another anchor token out of the price range as these checks use the current reserves.
Impact
Anchored pools are automatically curated pools and determine if a pool receives rewards.
An attacker can remove rewards of a curated pool this way and add rewards to their own pool with a custom token they control.
After a pool has been anchored through flash loans, liquidity can be withdrawn which could make the anchor price easy to manipulate in the next block and launch other attacks.
Recommended Mitigation Steps
Revisit the _isAnchor[token] = true; statement in addLiquidity, it seems strange without any further checks.
Consider making listAnchor / replaceAnchor DAO-only functions and make them flash-loan secure.
One should probably use time-weighted prices for these pools for the bounds check.
The protocol is intended to be launched with 5 anchors so it can only be attacked by using replaceAnchor(), in which case slip-based fees apply for attacks and thwart the attack path.
Handle
@cmichelio
Vulnerability details
Vulnerability Details
The
Router.listAnchor
function can be called by anyone and tokens can be added. The only check is thatrequire(iPOOLS(POOLS).isAnchor(token));
but this can easily be set by callingPools.addLiquidity(VADER, token, _)
once even without actually sending any tokens to the contract. This makes it an essentially useless check.This only works initially as long as the
anchorLimit
has not been reached yet. However, thereplaceAnchor
can be used in the same way and flash loans can be used to get around the liquidity restrictions and push another anchor token out of the price range as these checks use the current reserves.Impact
Anchored pools are automatically curated pools and determine if a pool receives rewards. An attacker can remove rewards of a curated pool this way and add rewards to their own pool with a custom token they control.
After a pool has been anchored through flash loans, liquidity can be withdrawn which could make the anchor price easy to manipulate in the next block and launch other attacks.
Recommended Mitigation Steps
Revisit the
_isAnchor[token] = true;
statement inaddLiquidity
, it seems strange without any further checks. Consider makinglistAnchor
/replaceAnchor
DAO-only functions and make them flash-loan secure. One should probably use time-weighted prices for these pools for the bounds check.