Dria

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

Lack of Maximum Score Check in `validate` Function of `LLMOracleCoordinator`

Github

Summary

The validate function in the LLMOracleCoordinator contract allows validators to submit scores for individual task generations. However, the function does not include a check to ensure that each score in the submission is within an acceptable range, specifically below a defined maximum score. This absence of validation introduces a potential vulnerability, as validators can submit excessively high scores that could manipulate or distort task outcomes. Implementing a maximum score check is essential to maintaining the integrity of the scoring process, ensuring accurate results, and preventing any manipulation that could affect task rewards or evaluations.

Vulnerability Details

The primary purpose of the validate function is to record validation scores submitted by validators for each generation within a task. Each validator submits an array of scores, where each score corresponds to a specific generation. For example, if a task requires three generations, the validator will submit an array of three scores, each indicating the validation score for one generation. However, the function currently lacks a boundary check for each individual score. This missing validation allows scores that exceed a reasonable maximum value, potentially skewing the task’s final outcome.

/// @notice Validate requests for a given taskId.
/// @dev Reverts if the task is not pending validation.
/// @dev Reverts if the number of scores is not equal to the number of generations.
/// @dev Reverts if any score is greater than the maximum score.
/// @param taskId The ID of the task to validate.
/// @param nonce The proof-of-work nonce.
/// @param scores The validation scores for each generation.
/// @param metadata Optional metadata for this validation.
function validate(uint256 taskId, uint256 nonce, uint256[] calldata scores, bytes calldata metadata)
public
onlyRegistered(LLMOracleKind.Validator)
onlyAtStatus(taskId, TaskStatus.PendingValidation)
{
TaskRequest storage task = requests[taskId];
// ensure there is a score for each generation
if (scores.length != task.parameters.numGenerations) {
revert InvalidValidation(taskId, msg.sender);
}
// ensure validator did not participate in generation
for (uint256 i = 0; i < task.parameters.numGenerations; i++) {
if (responses[taskId][i].responder == msg.sender) {
revert AlreadyResponded(taskId, msg.sender);
}
}
// ensure validator to be unique for this task
for (uint256 i = 0; i < validations[taskId].length; i++) {
if (validations[taskId][i].validator == msg.sender) {
revert AlreadyResponded(taskId, msg.sender);
}
}
// check nonce (proof-of-work)
assertValidNonce(taskId, task, nonce);
// update validation scores
validations[taskId].push(
TaskValidation({scores: scores, nonce: nonce, metadata: metadata, validator: msg.sender})
);
// emit validation event
emit Validation(taskId, msg.sender);
// update completion status
bool isCompleted = validations[taskId].length == task.parameters.numValidations;
if (isCompleted) {
task.status = TaskStatus.Completed;
emit StatusUpdate(taskId, task.protocol, TaskStatus.PendingValidation, TaskStatus.Completed);
// finalize validation scores
finalizeValidation(taskId);
}
}

Without a defined maximum score, validators are free to submit abnormally high scores that could influence the result calculations in ways that are unintended or exploitative. For instance, when scores are aggregated or averaged in later stages, excessively high scores can raise the overall mean or influence which responses are deemed the most successful. This could have substantial impacts, particularly if rewards or task completion depend on these scores.

Example

To illustrate, imagine a task with three generations, where each score is expected to be within a range of 0 to 100. A validator could submit scores [150, 90, 95], where the first score, 150, exceeds the anticipated maximum score of 100. Without a check in place, this score would be accepted and stored in the contract, leading to an inflated average or otherwise skewed result when all scores are later processed. The inflated score would unfairly affect the ranking or reward distribution for the task, potentially disadvantaging participants who completed valid responses.

In a real-world scenario, such unchecked scores could also lead to disputes over task outcomes, as other users or validators might identify the issue and question the fairness of the results. This inconsistency would not only introduce errors in the scoring mechanism but could also erode user trust in the platform.

Impact

The absence of a maximum score check in the validate function allows validators to submit excessively high scores, potentially distorting task outcomes and reward distributions. This vulnerability could be exploited to manipulate task results, leading to unfair rewards or biased responder selection. Additionally, unchecked scores undermine user trust in the platform's fairness and accuracy, as task requesters and other participants may encounter inconsistent validation results. Over time, this could erode confidence in the platform’s integrity and lead to reputational and financial harm.

Tools Used

Manual Review

Recommendations

To address this vulnerability, it is recommended that a maximum score check be implemented within the validate function. The function should iterate through each score in the submitted array and ensure it does not exceed a predefined MAX_SCORE value.

Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Unbounded score values in `validate` function

Support

FAQs

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