Skip to content
Security
Skill

/cross-chain-messaging

Detect cross-chain messaging bugs — replay protection gaps, untrusted-remote acceptance, default-config inheritance, validator-set misconfig, force-include vulnerabilities, chainId / domain-separator omissions. Activate on `_lzReceive`, `ccipReceive`, `handle` (Hyperlane),

From plugin
rugproof
952 skills23 agents45 commands4 hooks
Install
$ npx -y skills add omermaksutii/RugProof --skill cross-chain-messaging --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/cross-chain-messaging

Context preview

The summary Claude sees to decide when to auto-load this skill.

Detect cross-chain messaging bugs — replay protection gaps, untrusted-remote acceptance, default-config inheritance, validator-set misconfig, force-include vulnerabilities, chainId / domain-separator omissions. Activate on `_lzReceive`, `ccipReceive`, `handle` (Hyperlane),

SKILL.md

cross-chain-messaging.SKILL.md
name: cross-chain-messaging
description: Detect cross-chain messaging bugs — replay protection gaps, untrusted-remote acceptance, default-config inheritance, validator-set misconfig, force-include vulnerabilities, chainId / domain-separator omissions. Activate on `_lzReceive`, `ccipReceive`, `handle` (Hyperlane), `receiveMessage`, `verifyVAA`, IRouterClient, IMailbox, EndpointV2, OApp/OFT, LayerZero / CCIP / Hyperlane / Wormhole / Axelar / Polyhedra integration code.

Cross-chain messaging detection

When this applies

  • Any application built on LayerZero, CCIP, Hyperlane, Wormhole, Axelar, Polyhedra ZKBridge
  • Native L1↔L2 messengers (Optimism, Arbitrum, Base, zkSync, Linea, Scroll)
  • Custom bridges / message-passing layers

Detection patterns

`_lzReceive` accepts any remote (CRITICAL — LayerZero)

function _lzReceive(bytes calldata srcAddr, bytes calldata payload) internal {
    // no allowlist of trusted remote
    _executeMint(payload);   // ← any chain can mint
}

Required: `require(trustedRemote[srcChainId] == srcAddr)`.

CCIP `ccipReceive` callable directly (CRITICAL)

function ccipReceive(Any2EVMMessage calldata m) external {   // ← public, no router check
    _execute(m.data);
}

Required: `require(msg.sender == address(router))`.

Hyperlane `handle` without ISM check (CRITICAL)

Hyperlane's default ISM is permissive. Apps must set their own. If `handle` is called by mailbox without app-side validation, anyone can spoof messages.

Wormhole VAA double-spend (CRITICAL)

function complete(bytes calldata vaa) external {
    IWormhole.VM memory vm = wormhole.parseAndVerifyVM(vaa);
    _mint(vm.payload.to, vm.payload.amount);   // ← no per-VAA seen check
}

Required: track `usedVAAs[vm.hash] = true` after first use.

Replay across chains (CRITICAL)

Same payload accepted on multiple destination chains. Include destination `chainId` in the signed/verified payload.

Default DVN / ISM / config inheritance (HIGH)

Application doesn't set explicit DVN set (LayerZero V2) or ISM (Hyperlane). Default configs are often weak. Look for explicit `setSendLibrary`, `setReceiveLibrary`, `setEnforcedOptions`, `setInterchainSecurityModule`.

chainId mapping mistakes (HIGH)

LayerZero EIDs ≠ chainIds. CCIP uses chainSelectors. Map wrong → message goes to wrong chain or stuck forever.

Insufficient gas in `_lzSend` / `_options` (MEDIUM)

Receiver runs out of gas → message stuck (LayerZero V2 retry semantics).

Force-include on L1↔L2 messengers (HIGH)

Anyone can force-include an L1→L2 transaction. If app assumes only sequencer can trigger certain flows, force-include breaks the assumption.

L2→L1 withdrawal delay assumption (MEDIUM)

Optimism: 7-day challenge. Arbitrum: 7-day. App that assumes funds arrive instantly L2→L1 → invariant broken.

Pause authority not granular (MEDIUM-HIGH)

Single pause for all routes vs per-route → over- or under-blast-radius.

LayerZero V2 compose reentrancy (HIGH)

`_lzReceive` triggering a compose call back into `lzCompose` re-enters during the same message. Treat composed messages as reentrant calls.

Trusted remote table update authority (HIGH)

If `setTrustedRemote` is `onlyOwner` and owner is an EOA, the bridge can be silently rerouted. See [[centralization-risk]].

Severity rubric

| Pattern | Severity | |---|---| | Receive function accepts any remote | **Critical** | | Receive function callable directly (not router/mailbox) | **Critical** | | VAA / message not marked seen → double-spend | **Critical** | | Cross-chain replay (no destination chainId binding) | **Critical** | | Default ISM / DVN config (no app-side override) | **High** | | chainId/EID/chainSelector mapping mistake | **High** | | Compose reentrancy in LayerZero V2 | **High** | | Force-include L1→L2 assumption | **High** | | L2→L1 withdrawal-delay assumption | **Medium** | | Single-key trusted-remote update authority | **High** | | Insufficient gas in send → message stuck | **Medium** |

Remediation patterns

  • Always validate `msg.sender == router/mailbox/endpoint`.
  • Always validate `srcChain` and `srcAddress` against an allowlist.
  • Always include destination chainId in the verified payload.
  • Mark messages seen by `(srcChain, srcAddr, nonce/hash)`.
  • Configure DVN / ISM / executor explicitly per chain.
  • Use chainId-aware helpers for L2 block number / time.
  • Per-route pause + global emergency pause.
  • Trusted-remote updates via timelock + multisig.

False-positive notes

  • Canonical OApp / OFT / OFT-Adapter from LayerZero Labs handle most of the above; verify the app didn't override unsafely.
  • CCIP RouterClient / ARM are well-tested; the bug surface is in the app's `ccipReceive`.

Related

  • [[crosschain-messaging-specialist]] (subagent)
  • [[signature-replay]]
  • [[bridge-specialist]] (asset bridges built on top)
Read more
Ships withrugproof

Rugproof your code before someone else does. 🌐 Live site: omermaksutii.github.io/RugProof 📦 Latest: v1.0.0 — 45 commands · 23 agents · 45 skills · 13 MCP servers · tested, offline-first, with rule packs, a benchmark, non-EVM coverage, and post-deploy

Get the whole plugin

Other skills on rugproof.