Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: medium
Invalid

Updating `generationDeviationFactor` during Validation finalization can unfairly disqualify `generators` from rewards

Summary

A vulnerability exists in the validation process where the owner can front-run transactions to manipulate reward eligibility criteria. The owner can update generationDeviationFactor while the validation process is underway, potentially excluding generators who would have been eligible for rewards.

Vulnerability Details

Reward Calculation and Awarding in finalizeValidation():

---SNIP---
// compute the mean and standard deviation
(uint256 stddev, uint256 mean) = Statistics.stddev(generationScores);
for (uint256 g_i = 0; g_i < task.parameters.numGenerations; g_i++) {
// ignore lower outliers
>> if (generationScores[g_i] >= mean - generationDeviationFactor * stddev) {
_increaseAllowance(responses[taskId][g_i].responder, task.generatorFee);
}
}

This function uses generationDeviationFactor to set a threshold for reward eligibility.

However, the generationDeviationFactor can be updated by the owner via setDeviationFactors() at any time:

function setDeviationFactors(uint64 _generationDeviationFactor, uint64 _validationDeviationFactor)
public
onlyOwner
{
>> generationDeviationFactor = _generationDeviationFactor;
validationDeviationFactor = _validationDeviationFactor;
}

If the owner changes generationDeviationFactor mid-execution, it could lower the reward threshold, preventing certain generators from receiving rewards they would otherwise qualify for.

Sceanario

  1. A validator completes the required validations in validate().

  2. validate() then calls finalizeValidation().

  3. During this transaction, the owner updates generationDeviationFactor, impacting the reward eligibility check in finalizeValidation().

Impact

Generators who should be eligible for rewards based on the original generationDeviationFactor may be unfairly disqualified.

Tools Used

Manual Review

Recommendations

The contract should cache the generationDeviationFactor value at the beginning of the validate() function. This cached value should then be passed into finalizeValidation(), ensuring that the reward calculations use the same deviation factor, regardless of any mid-transaction updates by the owner.

function validate(uint256 taskId) external onlyRegisteredValidator {
+ // Cache the current generationDeviationFactor
+ uint64 cachedGenerationDeviationFactor = generationDeviationFactor;
---SNIP---
bool isCompleted = validations[taskId].length == task.parameters.numValidations;
if (isCompleted) {
task.status = TaskStatus.Completed;
emit StatusUpdate(taskId, task.protocol, TaskStatus.PendingValidation, TaskStatus.Completed);
+ // Pass the cached factor to finalize validation
- finalizeValidation(taskId);
+ finalizeValidation(taskId, cachedGenerationDeviationFactor);
}
}
- function finalizeValidation(uint256 taskId) private {
+ function finalizeValidation(uint256 taskId, uint64 cachedGenerationDeviationFactor) private {
---SNIP---
+ // Use cachedGenerationDeviationFactor in reward calculations
for (uint256 g_i = 0; g_i < task.parameters.numGenerations; g_i++) {
- if (generationScores[g_i] >= mean - generationDeviationFactor * stddev) {
+ if (generationScores[g_i] >= mean - cachedGenerationDeviationFactor * stddev) {
_increaseAllowance(responses[taskId][g_i].responder, task.generatorFee);
}
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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