Dria

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

Users can submit malicious responses and validations due to unrestricted registry, lack of POW difficulty, and lack of punishment for dishonest behavior

Summary

Any EOA could sign up to be a validator or generator in the registry. This means that malicious users can submit spam validations and responses just to claim rewards. There is currently no system set in place to discourage dishonest behavior in the protocol as well. The difficulty for generating valid nonces for POW is also very low allowing a larger number of users to potentially place this attack.

Vulnerability Details

The issue starts in the LLMOracleRegistry contract due to the fact that any user can sign up to be any kind of oracle.

function register(LLMOracleKind kind) public {
uint256 amount = getStakeAmount(kind);
// ensure the user is not already registered
if (isRegistered(msg.sender, kind)) {
revert AlreadyRegistered(msg.sender);
}
// ensure the user has enough allowance to stake
if (token.allowance(msg.sender, address(this)) < amount) {
revert InsufficientFunds();
}
token.transferFrom(msg.sender, address(this), amount);
// register the user
registrations[msg.sender][kind] = amount;
emit Registered(msg.sender, kind);
}

Once they are register, they can call either respond or validate without performing any of the necessary generations or validations needed for the protocol to work. This will take up space in the validation and responses array for actual oracle nodes who will provide honest information. It can also potentially reward these malicious actors for not performing any of the necessary work.

The current maximum difficulty for computing the correct nonce is also set as 10 in the market parameters. When we look at the POW validation we see it uses the following check:

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);
}
}

Lets take the maximum of 10 for example. To create a message less than max uint256 shifted by 10 bits, the probability of computing the correct nonce would be 1/2^10 which would be 1/1024. This is very easy to compute and would take most computers milliseconds to calculate. Below is an example using the existing computation in the index.ts file that includes helper functions for the tests

it("mine nonce", async function () {
const taskRequest = await coordinator.requests(taskId);
const validator = generators[0];
const nonce = await mineNonce(BigInt(10), taskRequest.requester, validator.address, taskRequest.input, taskId)
console.log(nonce);
})

It only takes milliseconds to complete

✔ mine nonce (38ms)

Impact

Malicious users could potentially steal rewards from honest validators and generators. It would be especially be easy for generators as no upper bound is enforced for the standard deviation of scores.

(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);
}
}

It could also render requests useless and buyer agents would not receive valid responses of assets to buy.

Tools Used

Manual Review

Recommendations

  • Add whitelist for node oracles

  • Increase maximum difficulty and minimum difficulty for POW

  • Incentivize honest behavior and punish dishonest behaviot (ex. slashing staking amount)

Updates

Lead Judging Commences

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

There is no oracle whitelisting

Support

FAQs

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