Open c4-submissions opened 1 year ago
raymondfam marked the issue as primary issue
raymondfam marked the issue as sufficient quality report
raymondfam marked the issue as duplicate of #406
kirk-baird marked the issue as satisfactory
kirk-baird marked the issue as not a duplicate
kirk-baird changed the severity to QA (Quality Assurance)
Lines of code
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L102-L106
Vulnerability details
The current design of the bridge doesn't allow for deterministic addresses for bridge contracts, since it will cause a conflict with nonce validation in the destination bridge.
Impact
Message replay is protected by using a nonce. The source bridge uses a monotonic increasing nonce that is sent in every bridged message, and the destination bridges checks if this nonce has been already executed:
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L102-L106
While the
isSpentNonce
is correctly scoped to the address of the source bridge in the source chain (chainToApprovedSender[srcChain]
), it doesn't consider the case that this address can be the same for different chains in both a planned or accidental scenarios.Source bridge contracts may have the same address in different networks if they are deployed deterministically in a planned way (using
CREATE2
), or also in an accidental way as part of a script that reproduces the same deployment steps from a unique deployer account (usingCREATE
from the same address and with the same nonce).If this is the case, messages from different source chains coming to the same destination chain will conflict with the nonce having the same key in the
isSpentNonce
mapping, leading to failures while executing the bridged messages.Proof of Concept
Source bridge addresses are the same in source chain 1 (
SC1
) and source chain 2 (SC2
).SC1
to destination chain (DC
) using any nonce valueN1
.DC
marks the nonce as consumedisSpentNonce[chainToApprovedSender[SC1]][N1] = true
.SC2
toDC
and encounters with nonce valueN1
.DC
checks if nonceN1
is already spent. Since both addresses are the samechainToApprovedSender[SC1] == chainToApprovedSender[SC2]
, which means thatisSpentNonce[chainToApprovedSender[SC2]][N1] == true
, and the message is rejected.Recommended Mitigation Steps
Scope the
isSpentNonce
mapping to include also the source chain so that nonces won't conflict if coming from the same source bridge address.Assessed type
Other