Omniscia Xcaliswap Audit
Gauge Manual Review Findings
Gauge Manual Review Findings
GEG-01M: Potential Denial-of-Service Attack of Rewards
Type | Severity | Location |
---|---|---|
Logical Fault | ![]() | Gauge.sol:L548-L551 |
Description:
The notifyRewardAmount
mechanism will automatically add a token if it does not already exist in the rewards
array without an upper limit on the total entries thus potentially creating a Denial-of-Service (DoS) attack on the _updateRewardForAllTokens
function.
Impact:
It is currently possible to add an unlimited number of reward tokens which could cause the contract to become inoperable wherever the _updateRewardForAllTokens
function is invoked, a trait highly undesirable for such a high-value system.
Example:
527function notifyRewardAmount(address token, uint amount) external lock {528 require(token != stake);529 require(amount > 0);530 if (rewardRate[token] == 0) _writeRewardPerTokenCheckpoint(token, 0, block.timestamp);531 (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint).max, true);532 _claimFees();533
534 if (block.timestamp >= periodFinish[token]) {535 _safeTransferFrom(token, msg.sender, address(this), amount);536 rewardRate[token] = amount / DURATION;537 } else {538 uint _remaining = periodFinish[token] - block.timestamp;539 uint _left = _remaining * rewardRate[token];540 require(amount > _left);541 _safeTransferFrom(token, msg.sender, address(this), amount);542 rewardRate[token] = (amount + _left) / DURATION;543 }544 require(rewardRate[token] > 0);545 uint balance = IERC20(token).balanceOf(address(this));546 require(rewardRate[token] <= balance / DURATION, "Provided reward too high");547 periodFinish[token] = block.timestamp + DURATION;548 if (!isReward[token]) {549 isReward[token] = true; 550 rewards.push(token);551 }552
553 emit NotifyReward(msg.sender, token, amount);554}
Recommendation:
We advise the reward tokens to be specified during the initialization of the contract with a maximum upper limit imposed via a contract-level constant
to ensure no malicious tokens can be added to the rewards
array and that all the expected reward tokens are defined during the creation of the contract rather than dynamically. Alternatively, we advise a dedicated and privileged function to be introduced that permits manually white-listing reward tokens that would then be accepted by the notifyRewardAmount
function. Either of the two solutions are sufficient to deal with the vulnerability described.
Alleviation:
The Xcaliswap team has implemented a constant
MAX_REWARD_TOKENS
upper bound on the rewards
array. Please note, since the require
statement uses <
operator for upper bound comparison the rewards
array can only contain a maximum of 15
values.