# zEVM cross-chain messages ignore the user-specified message and prevent calling the destination contract

zEVM ZetaSent cross-chain messages hardcode an empty message field, so destination contracts' onZetaMessage is never invoked, breaking messaging and risking locked/burned funds.

- Payout: Contest reward
- Severity: high
- Program: ZetaChain
- Credited: berndartmueller
- Disclosed: 2024-09-06
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-11-zetachain-findings/issues/413
- Library page: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-06
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:high tech:go tech:solidity technique:source-review vuln:business-logic

**Target:** x/crosschain keeper ProcessZetaSentEvent / ZetaConnectorZEVM.send
**Root cause:** ProcessZetaSentEvent constructs MsgVoteOnObservedInboundTx with a hardcoded empty string instead of the user-specified message from the ZetaSent event, so the destination connector sees an empty message and skips calling onZetaMessage.
**Steps:**
1. Call `ZetaConnectorZEVM.send` with a non-empty `message` in `SendInput`, emitting a `ZetaSent` event.
2. PostTxProcessing parses the event and calls `ProcessZetaSentEvent`.
3. Observe line 221 passes `""` as the message to `NewMsgVoteOnObservedInboundTx`.
4. On the destination chain, `ZetaConnectorEth.onReceive` checks the message; being empty, it does not call `destinationAddress.onZetaMessage`.
5. Result: cross-chain message never delivered; burned zEVM assets cannot be redeemed on receiver.
**How found:** Code review of the cross-chain post-processing path: traced ZetaSent event handling from PostTxProcessing into ProcessZetaSentEvent and noticed the message argument was hardcoded empty rather than taken from the event.
**Insight:** When auditing cross-chain bridges, trace each field of the user-supplied message struct all the way into the outbound message constructor; hardcoded empty/zero fields silently break delivery and can strand funds.
