# Decoder and executor byte-interpretation mismatch

Decoders that read bytes differently than the executor dispatches or parses them

_Area: Smart contract access control and control flow. Seen in 4 disclosed reports; one confirmed bounty: $1,000; latest 2025-01-31. Updated 2026-10-24._

## How it works
A decoder and an executor disagree about what a byte string means. The invariant that must hold: the bytes a decoder interprets are exactly the bytes the executor acts on, and the decoder runs only when dispatch rules guarantee it. Three ways it breaks: (1) the compiler routes calldata by its first 4 bytes to a real function before `fallback` runs, so a fallback that decodes `msg.data` from byte 0 assumes it owns all calldata it receives [E2](https://bugbountylibrary.com/r/sherlock%3A2024-03-woofi-swap%3AM-1.md); (2) a decoder assumes calldata length matches ABI parameter sizes, but legacy solc<0.5.0 contracts zero-pad short calldata and still execute, so a decoder that bails on odd lengths shows the user something different from what runs [E1](https://bugbountylibrary.com/r/h1%3A1651429.md); (3) a decoder reads the wrong buffer, applying TLV unpacking to a buffer whose base section is not TLV-encoded [E3](https://bugbountylibrary.com/r/cantina%3Atensor_nov2024%3A3.2.4.md).

## Where it shows up
- `fallback(bytes calldata _input)` that decodes `_input`/`msg.data` from offset 0 without a reserved prefix [E2](https://bugbountylibrary.com/r/sherlock%3A2024-03-woofi-swap%3AM-1.md)
- Wallet/UI ABI decoders that fall back to a generic display on length mismatch [E1](https://bugbountylibrary.com/r/h1%3A1651429.md)
- Calls to legacy (solc<0.5.0) contracts where short calldata is tolerated [E1](https://bugbountylibrary.com/r/h1%3A1651429.md)
- TLV/extension decoding applied to a raw account buffer instead of after base-state unpack [E3](https://bugbountylibrary.com/r/cantina%3Atensor_nov2024%3A3.2.4.md)
- Any path where a correct accessor exists but a sibling path decodes raw data directly [E3](https://bugbountylibrary.com/r/cantina%3Atensor_nov2024%3A3.2.4.md)

## How to review
State the invariant once and test each decoder against it. For fallbacks, confirm payloads carry a non-colliding prefix (e.g. `0x00000000`) and offsets account for it [E2](https://bugbountylibrary.com/r/sherlock%3A2024-03-woofi-swap%3AM-1.md). For decoders, verify behavior on truncated and oversized calldata matches the target contract's actual execution semantics, not a generic fallback [E1](https://bugbountylibrary.com/r/h1%3A1651429.md). For account parsing, confirm TLV reads use the base-aware accessor (`StateWithExtensions::unpack` then `get_tlv_data`) and grep for direct `TlvStateBorrowed::unpack` on raw buffers [E3](https://bugbountylibrary.com/r/cantina%3Atensor_nov2024%3A3.2.4.md).

## Variants seen
- Fallback ZIP decoder colliding with real selectors, misrouting price data [E2](https://bugbountylibrary.com/r/sherlock%3A2024-03-woofi-swap%3AM-1.md)
- Wallet decoder falling back to generic display on truncated calldata, hiding recipient/amount [E1](https://bugbountylibrary.com/r/h1%3A1651429.md)
- TLV unpack on full Mint buffer making a bid filter never match [E3](https://bugbountylibrary.com/r/cantina%3Atensor_nov2024%3A3.2.4.md)

## Impact and severity
E1 enabled phishing approvals without user alert; E2 risked unintended calls from crafted price blobs; E3 silently disabled a filter, blocking legitimate bids. Severity rises when the mismatch is user-facing (hidden approval) or lets attacker-supplied bytes reach a privileged path.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A1651429.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-03-woofi-swap%3AM-1.md
- E3: https://bugbountylibrary.com/r/cantina%3Atensor_nov2024%3A3.2.4.md
