Open c4-bot-6 opened 8 months ago
raymondfam marked the issue as insufficient quality report
raymondfam marked the issue as duplicate of #173
raymondfam marked the issue as sufficient quality report
raymondfam marked the issue as not a duplicate
raymondfam marked the issue as duplicate of #212
alex-ppg marked the issue as selected for report
This and all duplicate exhibits highlight that the GAS_FOR_RELAY
is a hard-coded value and that the overall gas supplied for a cross-chain call can be controlled by a user.
A severity of high is appropriate given that the cross-chain LayerZero channel will be permanently blocked.
None of the submissions have correctly proposed a solution as a mere adjustment of the GAS_FOR_RELAY
is insufficient. The DecentBridgeExecutor
permits arbitrary calls to be made that can force the transaction to run out-of-gas regardless of the gas limit imposed. This is properly defined in #697.
A valid solution for this problem would be a combination of a minimum enforced at the transaction level and a maximum gas consumed enforced at the executor level, ensuring that the gas remainder after the executor performs the arbitrary call is enough to store the failed message. This can be achieved by performing a subtraction from the gasleft
value (hard to implement as it would need to take into account the cost of keccak256
encoding the data payload) or by enforcing a fixed value that should be much less than the minimum imposed on the source chain.
This submission was selected as the best given that it illustrates in-depth knowledge of the LayerZero system states and correctly highlights that a user can also maliciously block the channel.
alex-ppg marked the issue as satisfactory
alex-ppg changed the severity to 3 (High Risk)
Hi @alex-ppg,
None of the submissions have correctly proposed a solution as a mere adjustment of the GAS_FOR_RELAY is insufficient. The DecentBridgeExecutor permits arbitrary calls to be made that can force the transaction to run out-of-gas regardless of the gas limit imposed. This is properly defined in https://github.com/code-423n4/2024-01-decent-findings/issues/697.
I believe this is not factually correct, I have left a comment here: https://github.com/code-423n4/2024-01-decent-findings/issues/697#issuecomment-1929936744.
Thanks!
Hey @windhustler, thanks for contributing! I have responded to the original comment at #697. Please keep discussions in a single place to prevent duplication of effort.
cdsiren marked the issue as disagree with severity
cdsiren marked the issue as disagree with severity
This vulnerability is not a concern in Layer Zero v2. Decent designed the contracts expecting to use LZ v2 and have since implemented this upgrade.
Lines of code
https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L148-L194 https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L80-L111
Vulnerability details
Impact
In LayerZero, the destination chain's function call requires a specific gas amount; otherwise, it will revert with an out-of-gas exception. It falls under the responsibility of the User Application to ensure that appropriate limits are established. These limits guide relayers in specifying the correct gas amount on the source chain, preventing users from inputting insufficient values for gas.
The contract logic in
DecentEthRouter
, assumes that a user will first get their estimated fees throughestimateSendAndCallFee()
and pass it as an argument in eitherbridge()
orbridgeWithPayload()
to be added to the calculation together with the hardcodedGAS_FOR_RELAY
so that it can be passed as the adapter params whenCommonOFT.LzCallParams
is called, although this is not enforced and is left on the user's responsibility.A user can pass an arbitrary value as the
_dstGasForCall
argument to be added to the hardcodedGAS_FOR_RELAY
fee, thus sending less gas than required which can lead to out-of-gas exceptions.Once the message is received by destination, the message is considered delivered (transitioning from INFLIGHT to either SUCCESS or STORED), even though it threw an out-of-gas error.
Any uncaught errors/exceptions (including out-of-gas) will cause the message to transition into STORED. A STORED message will block the delivery of any future message from source to all destination on the same destination chain and can be retried until the message becomes SUCCESS.
As per: https://layerzero.gitbook.io/docs/faq/messaging-properties
Proof of Concept
According to the LayerZero integration checklist: https://layerzero.gitbook.io/docs/troubleshooting/layerzero-integration-checklist
LayerZero recommends a 200,000 amount of gas to be enough for most chains and is set as default.
In the DecentEthRouter, the
GAS_FOR_RELAY
is hardcoded at 100,000.The contract logic assumes that a user would willingly first call the
estimateSendAndCallFee
to get thenativeFee
+ thezroFee
fomdcntEth.estimateSendAndCallFee
and then pass the addition of the nativeFee + zeroFee as the_dstGasForCall
argument when callingbridge()
orbridgeWithPayload()
:Once the internal
_bridgeWithPayload
function is called:It calls the
_getCallParams
function which will calculate and pack the needed arguments to be passed as the LayerZero call params, without performing any checks whether the total gas amount is sufficient or that the user passed argument_dstGasForCall
is greater than the total of(uint nativeFee, uint zroFee) = dcntEth.estimateSendAndCallFee
.This can lead to failed messages on the destination. Which would yield the above-message results of a possible blockage in the communication with the source and destination.
_dstGasForCall
, making the total gas forwarded to theLzCallParams()
101,000 which will make a certain type of calls fail (depending on payload), and especially calls made on Arbitrum.Tools Used
Manual Review
Recommended Mitigation Steps
Validate/require that the
_dstGasForCall
parameter is greater thannativeFee
+zroFee
or re-engineer the architecture to make theestimateSendAndCallFee()
function a mandatory step of the process.Assessed type
Invalid Validation