Project

One World
NFTDeFi
15,000 USDC
View results
Submission Details
Severity: medium
Invalid

Premature Nonce Increment in executeMetaTransaction

Summary

The executeMetaTransaction function in the NativeMetaTransaction contract increments the user’s nonce immediately after verifying the signature but before executing the actual function call. If the function call fails (e.g., due to a revert), the nonce will already have incremented, making it impossible for the user to resubmit the same meta-transaction. This can lead to a Denial of Service (DoS) vulnerability by preventing valid transactions from completing.

This premature nonce increment results in a potential loss of user convenience and functionality, as legitimate meta-transactions cannot be retried without requiring the user to sign a new meta-transaction.

Vulnerability Details

In the executeMetaTransaction function, the line:

require(verify(userAddress, metaTx, sigR, sigS, sigV), "Signer and signature do not match");
// increase nonce for user (to avoid re-use)
nonces[userAddress] = nonces[userAddress] + 1;

Impact

if the function call fails after the nonce is incremented, the transaction cannot be retried with the same signature, resulting in a Denial of Service (DoS) for legitimate transactions.

Tools Used

Manual review

Recommendations

the nonce should be incremented only after the function call is successfully executed. This way, if the function call fails, the nonce remains unchanged, allowing the user to retry the transaction.

Modify the executeMetaTransaction function as follows:

function executeMetaTransaction(
address userAddress,
bytes memory functionSignature,
bytes32 sigR,
bytes32 sigS,
uint8 sigV
) public payable returns (bytes memory) {
MetaTransaction memory metaTx =
MetaTransaction({nonce: nonces[userAddress], from: userAddress, functionSignature: functionSignature});
require(verify(userAddress, metaTx, sigR, sigS, sigV), "Signer and signature do not match");
// Emit event before execution to record the attempt, not just successful execution
emit MetaTransactionExecuted(userAddress, msg.sender, functionSignature, hashMetaTransaction(metaTx));
// Append userAddress and relayer address at the end to extract it from calling context
(bool success, bytes memory returnData) =
address(this).call{value: msg.value}(abi.encodePacked(functionSignature, userAddress));
// Increment nonce only if function call succeeds
require(success, "Function call not successful");
nonces[userAddress] += 1;
return returnData;
}
Updates

Lead Judging Commences

0xbrivan2 Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
0xbrivan2 Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!