# Caller-supplied chain id routing

Cross-chain code branching or routing on a chain id taken from caller input instead of the contract's own stored chain

_Area: Smart contract access control and control flow. Seen in 2 disclosed reports; latest 2025-07-22. Updated 2026-11-01._

## How it works
A cross-chain contract must decide "am I the local chain or a remote one?" and "where may these funds go?" The safe answer comes from state the contract controls: its own stored chain identifier, or a fixed allowlist of handled chains. The weakness is that the decision is instead made from a value the caller supplies — a destination chain id parameter, or an array of destinations — so the caller, not the contract, chooses the routing. The broken assumption is that caller input describes the contract's own situation; in fact it describes whatever the caller wants.

## Where it shows up
- A branch like `if (_chainId == ...)` inside a push/send function, where `_chainId` is a function parameter rather than a stored `homeChain` [E3](https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AM-40.md).
- Bridge/relayer functions that accept an array of destinations but validate only that the requested id is a member of the array [E2](https://bugbountylibrary.com/r/sherlock%3A2025-07-malda%3AM-5.md).
- Cross-chain compose handlers that read a `user`/`from` field out of caller-supplied structs and forward it to a privileged, whitelisted executor [E1](https://bugbountylibrary.com/r/c4%3A2024-02-tapioca%3AH-01.md).
- Any `_checkSender`-style whitelist that grants a relayer blanket authority over arbitrary `_from` values [E1](https://bugbountylibrary.com/r/c4%3A2024-02-tapioca%3AH-01.md).

## How to review
For each cross-chain entry point, identify every routing or authorization decision and ask what its inputs are. The invariant: local-vs-remote branching and destination eligibility must be derived only from contract-controlled state (stored chain id, configured allowlist), never from a caller parameter. For arrays, check that the *entire* forwarded array is validated, not just membership of one element — the downstream protocol honors the whole array [E2](https://bugbountylibrary.com/r/sherlock%3A2025-07-malda%3AM-5.md). For relayed structs, every field that reaches a privileged call (especially `user`/`from`) must be checked against the original caller, because the relay's whitelist privilege overrides per-user checks [E1](https://bugbountylibrary.com/r/c4%3A2024-02-tapioca%3AH-01.md).

## How finders spotted it
- Read the whitelist logic in `_checkSender`, traced the compose flow, and noticed the compose message encoded a `user` field without validation while the executor was whitelisted [E1](https://bugbountylibrary.com/r/c4%3A2024-02-tapioca%3AH-01.md).
- Read `sendMsg`, saw `destinations` is an array but validation only checks membership of `_dstChainId`, then reasoned the full array is forwarded downstream [E2](https://bugbountylibrary.com/r/sherlock%3A2025-07-malda%3AM-5.md).
- Read the push functions and noticed the branch condition used the parameter `_chainId` instead of the contract's `homeChain` [E3](https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AM-40.md).

## Variants seen
- Scalar parameter used for local/remote routing instead of stored chain id, causing reverts or calls to `address(0)` [E3](https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AM-40.md).
- Array-vs-scalar validation mismatch letting funds route to unhandled chains [E2](https://bugbountylibrary.com/r/sherlock%3A2025-07-malda%3AM-5.md).
- Caller-controlled `user` field in a relayed struct reaching a whitelisted executor that acts on the victim's behalf [E1](https://bugbountylibrary.com/r/c4%3A2024-02-tapioca%3AH-01.md).

## Impact and severity
E3 halts vault progression (availability). E2 loses funds by settling on chains Malda does not handle. E1 lets an attacker manipulate other users' positions through a trusted relay; impact is raised because the relay's privilege bypasses per-user authorization and the same pattern applies to any other path triggering the whitelisted executor [E1](https://bugbountylibrary.com/r/c4%3A2024-02-tapioca%3AH-01.md).

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2024-02-tapioca%3AH-01.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2025-07-malda%3AM-5.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AM-40.md
