Dria

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

In the `LLMOracleCoordinator::validate` function, a check to revert if any score exceeds the maximum allowed score is not implemented

Summary

As stated in the NatSpec for the LLMOracleCoordinator::validate function, it should revert if any score exceeds the maximum score; however, this check is not implemented in the function.

Vulnerability Details

Without implementing a check to revert if any score exceeds the maximum, users can input excessively large values, potentially disrupting further calculations within the function or cause or cause overflow condition in the calculations.

Also The maximum Score is not defined any where in the contract.There is no way to check that the score entered by the user is above maximum or not.

/// @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);
}
// a- the params is wrong there should be generators
// 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);
}
}

Impact

Users can input excessively large scores, which may cause malfunctions in the validate and finalizeValidation functions.

A large score value can disrupt the calculation of the mean and standard deviation in finalizeValidation, leading to incorrect selection of suitable validations.

Tools Used

manual review

Recommendations

First, define a MaximumScore variable and allow the owner to set it to an appropriate value. Here’s an example of how this can be implemented:

set it in the initialize function of contract.

+// Define the maximum allowable score, settable by the owner
+uint256 public MaximumScore;
function initialize(
address _oracleRegistry,
address _feeToken,
uint256 _platformFee,
uint256 _generationFee,
uint256 _validationFee,
+ uint256 _MaximumScore
) public initializer {
__Ownable_init(msg.sender);
__LLMOracleManager_init(_platformFee, _generationFee, _validationFee);
registry = LLMOracleRegistry(_oracleRegistry);
feeToken = ERC20(_feeToken);
nextTaskId = 1;
+ MaximumScore = _MaximumScore
}

second, make a for loop which will check the scores array values.

/// @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 the score entered is less than MaximumScore
+ for(uint256 i=0; i < scores.length ; i++ ){
+ require(scores[i] < MaximumScore, "invalid score");
+ }
// a- the params is wrong there should be generators
// 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);
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 9 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.