Project

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

Potential for Meta-Transaction Replay Across Chains

Summary

The NativeMetaTransaction contract, as currently implemented, is vulnerable to cross-chain replay attacks. This issue arises because the meta-transaction hash does not include the chainId, allowing the same signed meta-transaction to be valid across different blockchain networks.

Vulnerability Details

If the project is currently limited to a single blockchain, such as Polygon, the risk of a cross-chain replay attack is not immediately applicable, since the meta-transaction can only be executed on that one network.

However, it’s important to consider potential future plans. If there’s any chance the project will expand to multiple blockchains or intends to scale across networks, the cross-chain replay protection will become relevant. Including the chainId in the meta-transaction structure would "future-proof" the contract, preventing the need for potentially costly upgrades or refactoring later.

In a cross-chain setup, if a user signs a meta-transaction on one network, a malicious actor could replay the transaction on a different network, leading to unintended function calls and potentially causing loss or duplication of actions across chains. This vulnerability is significant for contracts that interact across multiple chains, as it could compromise user security and system integrity.

Impact

The executeMetaTransaction function creates a MetaTransaction struct that is subsequently hashed in the hashMetaTransaction function. However, the hash calculation does not currently include the chain ID (chainId), making the signature valid across chains.

Without the chainId, the following risks are possible:

  1. Cross-Chain Replay Attack: The same signed meta-transaction could be valid on multiple chains, allowing unauthorized executions on chains where the user did not intend to transact.

  2. Inconsistent State Across Chains: If the same transaction executes on multiple chains, it could result in state discrepancies or unintended duplications of actions.

Tools Used

Manual review

Recommendations

Add chainId to MetaTransaction struct and update the hashMetaTransaction function to include chainId in the encoding process::

struct MetaTransaction {
uint256 nonce;
address from;
bytes functionSignature;
+++ uint256 chainId;
}
function hashMetaTransaction(MetaTransaction memory metaTx)
public
pure
returns (bytes32)
{
return
keccak256(
abi.encode(
META_TRANSACTION_TYPEHASH,
metaTx.nonce,
metaTx.from,
keccak256(metaTx.functionSignature),
+++ metaTx.chainId
)
);
}

Set chainId in executeMetaTransaction: When creating the MetaTransaction instance in executeMetaTransaction, set chainId to the current chain’s ID:

MetaTransaction memory metaTx = MetaTransaction({
nonce: nonces[userAddress],
from: userAddress,
functionSignature: functionSignature,
+++ chainId: block.chainid
});
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!