sherlock-audit / 2024-09-orderly-network-solana-contract-judging

0 stars 0 forks source link

Fit Canvas Pangolin - The absence of the addExecutorOrderedExecutionOption parameter causes the ordered delivery mode to fail. #96

Open sherlock-admin2 opened 4 days ago

sherlock-admin2 commented 4 days ago

Fit Canvas Pangolin

Medium

The absence of the addExecutorOrderedExecutionOption parameter causes the ordered delivery mode to fail.

Summary

The absence of the addExecutorOrderedExecutionOption parameter causes the ordered delivery mode to fail, This may cause user funds to become stuck in the protocol.

Root Cause

According to the LayerZero documentation: https://docs.layerzero.network/v2/developers/evm/oapp/message-design-patterns#message-ordering

To implement strict nonce enforcement, you need to implement the following:

a mapping to track the maximum received nonce.

override _acceptNonce and nextNonce.

add ExecutorOrderedExecutionOption in _options when calling _lzSend.

However, in the EVM side oApp of the orderly chain:

https://github.com/sherlock-audit/2024-09-orderly-network-solana-contract/blob/main/sol-cc/contracts/SolConnector.sol#L92

@>> bytes memory withdrawOptions = OptionsBuilder.newOptions().addExecutorLzReceiveOption(
            msgOptions[uint8(MsgCodec.MsgType.Withdraw)].gas,
            msgOptions[uint8(MsgCodec.MsgType.Withdraw)].value
        );
        MessagingFee memory _msgFee = _quote(solEid, lzWithdrawMsg, withdrawOptions, false);
        _lzSend(solEid, lzWithdrawMsg, withdrawOptions, _msgFee, address(this));

The ExecutorOrderedExecutionOption option was not added. Similarly, in the Solana oApp: https://github.com/sherlock-audit/2024-09-orderly-network-solana-contract/blob/main/solana-vault/packages/solana/contracts/programs/solana-vault/src/instructions/vault_instr/deposit.rs#L141

@>>       let options = EnforcedOptions::get_enforced_options(&ctx.accounts.enforced_options, &None);

        let endpoint_send_params = EndpointSendParams {
            dst_eid: ctx.accounts.vault_authority.dst_eid,
            receiver: ctx.accounts.peer.address,
            message: lz_message,
@>>            options: options,
            native_fee: oapp_params.native_fee,
            lz_token_fee: oapp_params.lz_token_fee,
        };

        let receipt = oapp::endpoint_cpi::send(
            ctx.accounts.oapp_config.endpoint_program,
            ctx.accounts.oapp_config.key(),
            ctx.remaining_accounts,
            seeds,
            endpoint_send_params,
        )?;

The ExecutorOrderedExecutionOption option was also not added. As a result, the ordered delivery mode will fail, especially since the ordered delivery mode is enabled by default in the EVM-side oApp on the orderly chain.

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

  1. The ordered delivery mode on both the Solana and EVM-side oApp cannot function properly.

  2. This further impacts users by causing their funds to be stuck in the protocol. Here’s an example with deposit(): • (1) Users A and B deposit 1000 USDC almost simultaneously. • (2) LayerZero’s execute function assigns the same nonce to both transactions via nextNonce(), assumed to be 1 for both. • (3) On the EVM side, only one of the messages from User A or User B will execute successfully. After one execution succeeds, inboundNonce increments to 1, but _origin.nonce remains 1. This results in the require(_origin.nonce == inboundNonce + 1) check failing, causing one user’s funds to remain stuck on the Solana side, unable to reach the orderly EVM side.

PoC

No response

Mitigation

Append to your Message Options an ExecutorOrderedExecutionOption in your _lzSend call,like:

// appends "01000104", the ExecutorOrderedExecutionOption, to your options bytes array
_options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 0).addExecutorOrderedExecutionOption();