Bug Bounty Submission: Same-Nonce Message Replay Vulnerability in Bridged Reputation Root Hash Update
Prerequisite
I ensured that this issue, specifically the weak nonce check (>=) in setReputationRootHashFromBridge allowing same-nonce replays, has not already been reported.
Summary
The setReputationRootHashFromBridge function within the ColonyNetworkMining.sol contract utilizes a non-strict nonce check (require(_nonce >= bridgeCurrentRootHashNonces[...])) for processing reputation root hash updates received via the bridge. This implementation flaw allows a message with a specific nonce to be processed multiple times consecutively if it is resubmitted before a message with a strictly higher nonce is processed. This enables a replay attack that forces the contract to re-execute logic, consume gas unnecessarily, and emit duplicate events, violating the integrity of the nonce mechanism and potentially impacting dependent off-chain systems. This constitutes a High Risk vulnerability according to the OWASP Risk Rating methodology.
Steps to Reproduce (Conceptual PoC)
This Proof of Concept demonstrates how a message with the same nonce can be processed multiple times. Let Chain M be the source chain and Chain C be the target chain where this code runs.
-
Initial State: Chain C has processed messages from Chain M up to nonce N. The state variable bridgeCurrentRootHashNonces[<Chain_M_ID>] on Chain C holds N. The reputation state is (HASH_OLD, LEAVES_OLD).
-
Valid Message Sent: Chain M sends Msg1 = (HASH_A, LEAVES_A, nonce=N+1) via the bridge to Chain C.
-
First Successful Processing on Chain C:
WormholeBridgeForColony calls ColonyNetworkMining.setReputationRootHashFromBridge(HASH_A, LEAVES_A, N+1).
- Check:
require(N+1 >= N) passes.
- State updated to (HASH_A, LEAVES_A). Nonce map updated to N+1. Event
ReputationRootHashSet(HASH_A, ...) emitted.
-
Replay Attempt: Before a message with nonce N+2 is sent/processed, an attacker resubmits the exact same Msg1 (containing nonce=N+1) to Chain C.
-
Second (Replay) Processing on Chain C:
WormholeBridgeForColony calls ColonyNetworkMining.setReputationRootHashFromBridge(HASH_A, LEAVES_A, N+1) again.
- Check:
require(nonce (N+1) >= bridgeCurrentRootHashNonces[<Chain_M_ID>] (N+1)) passes due to >=. <- Vulnerability.
- State (HASH_A, LEAVES_A) is reapplied (no change). Nonce map set to N+1 (no change). Event
ReputationRootHashSet(HASH_A, ...) is emitted again. Gas is consumed.
Expected Behavior
The nonce mechanism should strictly prevent the same message (identified by its nonce and origin) from being processed more than once. A check like require(_nonce > bridgeCurrentRootHashNonces[...]) should be used to ensure each nonce is processed at most once, rejecting replays of the exact same nonce.
Current Behaviour
The use of >= in the nonce check allows a message with nonce N+1 to be successfully processed even if the current stored nonce is already N+1, permitting consecutive replays.
Possible Solution
Modify the nonce check in ColonyNetworkMining.setReputationRootHashFromBridge to require the incoming nonce to be strictly greater than the last processed nonce:
// Inside setReputationRootHashFromBridge function
// Note: Assuming the map key is correctly representing the source chain ID in the actual implementation.
uint256 sourceChainId = ...; // Determine source chain ID correctly
uint256 lastProcessedNonce = bridgeCurrentRootHashNonces[sourceChainId];
require(_nonce > lastProcessedNonce, "colony-mining-bridge-nonce-must-be-greater");
bridgeCurrentRootHashNonces[sourceChainId] = _nonce;
Context
Environment
- Operating System: N/A (Blockchain/Solidity bug)
- Ethereum client: N/A (Applies to any EVM chain where deployed)
- solc version: 0.8.28 (as specified in pragmas)
Please consider rewarding this submission to your Bug Bounty Program accordingly as a High Severity vulnerability. Kindly issue the bounty to the following address: 0x36c81e0ec22cac063a0588b6165ce3fd022ab5b0
Bug Bounty Submission: Same-Nonce Message Replay Vulnerability in Bridged Reputation Root Hash Update
Prerequisite
I ensured that this issue, specifically the weak nonce check (>=) in
setReputationRootHashFromBridgeallowing same-nonce replays, has not already been reported.Summary
The
setReputationRootHashFromBridgefunction within theColonyNetworkMining.solcontract utilizes a non-strict nonce check (require(_nonce >= bridgeCurrentRootHashNonces[...])) for processing reputation root hash updates received via the bridge. This implementation flaw allows a message with a specific nonce to be processed multiple times consecutively if it is resubmitted before a message with a strictly higher nonce is processed. This enables a replay attack that forces the contract to re-execute logic, consume gas unnecessarily, and emit duplicate events, violating the integrity of the nonce mechanism and potentially impacting dependent off-chain systems. This constitutes a High Risk vulnerability according to the OWASP Risk Rating methodology.Steps to Reproduce (Conceptual PoC)
This Proof of Concept demonstrates how a message with the same nonce can be processed multiple times. Let Chain M be the source chain and Chain C be the target chain where this code runs.
Initial State: Chain C has processed messages from Chain M up to nonce N. The state variable
bridgeCurrentRootHashNonces[<Chain_M_ID>]on Chain C holds N. The reputation state is (HASH_OLD, LEAVES_OLD).Valid Message Sent: Chain M sends Msg1 = (HASH_A, LEAVES_A, nonce=N+1) via the bridge to Chain C.
First Successful Processing on Chain C:
WormholeBridgeForColonycallsColonyNetworkMining.setReputationRootHashFromBridge(HASH_A, LEAVES_A, N+1).require(N+1 >= N)passes.ReputationRootHashSet(HASH_A, ...)emitted.Replay Attempt: Before a message with nonce N+2 is sent/processed, an attacker resubmits the exact same Msg1 (containing nonce=N+1) to Chain C.
Second (Replay) Processing on Chain C:
WormholeBridgeForColonycallsColonyNetworkMining.setReputationRootHashFromBridge(HASH_A, LEAVES_A, N+1)again.require(nonce (N+1) >= bridgeCurrentRootHashNonces[<Chain_M_ID>] (N+1))passes due to >=. <- Vulnerability.ReputationRootHashSet(HASH_A, ...)is emitted again. Gas is consumed.Expected Behavior
The nonce mechanism should strictly prevent the same message (identified by its nonce and origin) from being processed more than once. A check like
require(_nonce > bridgeCurrentRootHashNonces[...])should be used to ensure each nonce is processed at most once, rejecting replays of the exact same nonce.Current Behaviour
The use of >= in the nonce check allows a message with nonce N+1 to be successfully processed even if the current stored nonce is already N+1, permitting consecutive replays.
Possible Solution
Modify the nonce check in
ColonyNetworkMining.setReputationRootHashFromBridgeto require the incoming nonce to be strictly greater than the last processed nonce:Context
OWASP Risk Rating:
Severity Classification: Based strictly on the OWASP Risk Rating methodology, a High Risk corresponds to a High Severity classification for this vulnerability.
Environment
Please consider rewarding this submission to your Bug Bounty Program accordingly as a High Severity vulnerability. Kindly issue the bounty to the following address: 0x36c81e0ec22cac063a0588b6165ce3fd022ab5b0