Dria

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

Lack of Nonce Uniqueness Verification in `LLMOracleCoordinator.assertValidNonce`

Summary

In the LLMOracleCoordinator contract, the assertValidNonce function is responsible for validating the proof-of-work (PoW) submitted by Oracles during the respond and validate operations.

The function constructs a message by concatenating the taskId, input, requester, msg.sender, and nonce, then computes the keccak-256 hash of this message. It ensures that the resulting hash is below a threshold determined by the task's difficulty parameter:

function assertValidNonce(uint256 taskId, TaskRequest storage task, uint256 nonce) internal view {
bytes memory message = abi.encodePacked(taskId, task.input, task.requester, msg.sender, nonce);
if (uint256(keccak256(message)) > type(uint256).max >> uint256(task.parameters.difficulty)) {
revert InvalidNonce(taskId, nonce);
}
}

But, it doesn't prevents oracles from reusing the same nonce.

Vulnerability Details

The assertValidNonce function verifies that the nonce meets the PoW requirement for a specific task and Oracle, but it does not ensure that each nonce is unique across different tasks or within the same task. This lack of uniqueness verification allows an Oracle to potentially reuse the same nonce across multiple tasks, provided that the concatenated message still satisfies the difficulty condition.

  • The Oracle identifies multiple tasks where the taskId, input, requester, and other concatenated parameters are such that reusing the same nonce would still produce a hash below the required difficulty threshold.

  • The Oracle submits responses or validations for different tasks using the same nonce value.

  • By reusing a nonce that already satisfies the PoW for one task, the Oracle reduces the computational effort required to respond to additional tasks, potentially increasing response frequency or reducing operational costs.

The assertValidNonce function ties the nonce to the specific parameters of a task. However, if multiple tasks share identical or sufficiently similar parameters, the same nonce could be valid across these tasks. This undermines the intended PoW mechanism, which relies on unique nonces to ensure that each Oracle response requires fresh computational effort.

Impact

The vulnerability is limited to scenarios where multiple tasks have overlapping or identical parameters, allowing nonce reuse. Given that taskId is unique and typically incremented, the likelihood of nonce reuse across distinct tasks is minimal unless tasks are intentionally crafted with identical parameters. While nonce reuse can marginally weaken the PoW mechanism, it does not compromise the core functionalities of task execution, fee distribution, or asset management within the Swan protocol.

Tools Used

Manual Review

Recommendations

Introduce a mapping to track used nonces for each Oracle per task. This ensures that a nonce cannot be reused within the same task.

+ mapping(uint256 => mapping(address => mapping(uint256 => bool))) public usedNonces;
function assertValidNonce(uint256 taskId, TaskRequest storage task, uint256 nonce) internal {
+ require(!usedNonces[taskId][msg.sender][nonce], "Nonce already used for this task");
bytes memory message = abi.encodePacked(taskId, task.input, task.requester, msg.sender, nonce);
require(uint256(keccak256(message)) <= type(uint256).max >> uint256(task.parameters.difficulty), "Invalid nonce");
+ usedNonces[taskId][msg.sender][nonce] = true;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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