# Proposal calldata swapped before execution

Does execution read parameters that the proposal hash or timelock actually committed?

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

## How it works
A governance or timelock flow splits an action into two steps: a *commitment* (a proposal, hash, or stored record) and an *execution* (the call that actually runs). The safety assumption is that what was approved is what runs. That breaks when the commitment binds only *some* of the executed inputs. If a parameter read at execution time is not covered by the commitment, whoever controls that parameter can change the action after approval, and the approval becomes a rubber stamp for something else. The timelock then protects *when* something runs, not *what* runs.

## Where it shows up
- Proposal structs that store a hash or a subset of fields (targets, selectors, init addresses) while the executed `_calldata` is passed in separately at execution time.
- Timelock/queue designs where the queued item and the executed item are assembled from different sources.
- "Best/most votes" or "winner" selectors that loop over a set without filtering by eligibility or deadline.
- Fixed-size arrays (e.g. a single `bytes32[] proof`) in a struct that a documented design says must carry N items.

## How to review
Trace every value the execution path reads and ask: *is this value bound by the commitment that was approved?* The invariant: **the executed call must be a pure function of the committed data** — same targets, same calldata, same value, byte for byte. If any executed parameter can differ between propose and execute, the commitment is incomplete. For selectors and proof structs, check the container can hold the maximum the design allows; a fixed-size field silently caps it.

## How finders spotted it
- Read `proposeDiamondCut` and noticed `_calldata` was deliberately left free between propose and execute; reasoned a leaked-key attacker could swap it at execution, defeating the notice period [E1](https://bugbountylibrary.com/r/c4%3A2022-10-zksync%3AM-01.md).
- Read `_finalizeTokenWhitelisting`'s require against `tokenWhitelistingBallotWithTheMostVotes()`, saw the loop ignored `ballotMinimumEndTime`, so in-flight ballots were compared against expired ones [E2](https://bugbountylibrary.com/r/c4%3A2024-01-salty%3AM-14.md).
- Read the cross-chain docs describing a multi-leaf Merkle tree, then traced `_decodeSignatureData` and saw `proofDst` was a single array, contradicting the documented design [E3](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.20.md).

## Variants seen
- Mutable calldata in a governor upgrade path, unbound by the proposal commitment [E1](https://bugbountylibrary.com/r/c4%3A2022-10-zksync%3AM-01.md).
- Winner-selection loop including not-yet-eligible ballots, letting a decoy block finalization [E2](https://bugbountylibrary.com/r/c4%3A2024-01-salty%3AM-14.md).
- Signature/proof struct too small to carry all leaves, capping a multi-message design to two [E3](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.20.md).

## Impact and severity
E1 lets a leaked-key attacker front-run execution with malicious calldata, bypassing the timelock notice — high, because it converts a key compromise into an immediate arbitrary upgrade [E1](https://bugbountylibrary.com/r/c4%3A2022-10-zksync%3AM-01.md). E2 is griefing: a minority staker can push finalization arbitrarily far into the future by repeating decoy ballots [E2](https://bugbountylibrary.com/r/c4%3A2024-01-salty%3AM-14.md). E3 breaks core multi-chain functionality outright, since multi-message userOps can never be fully proven [E3](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.20.md). Impact rises with how much the commitment was trusted to constrain the action.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2022-10-zksync%3AM-01.md
- E2: https://bugbountylibrary.com/r/c4%3A2024-01-salty%3AM-14.md
- E3: https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.20.md
