# Config encoding collision changes trust

Non-injective encoding or truncated field lets caller rewrite config, stake, or identity

_Area: Smart contract access control and control flow. Seen in 2 disclosed reports; latest 2024-06-12. Updated 2026-10-25._

## How it works
A value that should identify something (a game type, a remote peer address, a pool config) is packed, cast, or combined into a smaller or single scalar. The encoding is not injective: distinct inputs map to the same output. A check that compares only the encoded form then treats two different things as equal, so a caller can substitute one for the other and pass a trust check.

## Where it shows up
- Assembly casts that narrow a type (uint32 to uint8) at comparison sites [E1](https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-1.md)
- Slicing a packed address blob with the wrong offset, reading the destination instead of the source [E2](https://bugbountylibrary.com/r/c4%3A2023-09-maia%3AM-11.md)
- Integrity codes built as linear combinations like `a*K+b` [E3](https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.8.md)
- Any "unchanged config" check that hashes or sums several fields into one number
- Off-chain watchers keyed on the same truncated value as on-chain checks [E1](https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-1.md)

## How to review
Identify every place a multi-field or wide value is reduced to a scalar or narrower type, then ask whether the mapping is injective. The invariant: two distinct logical inputs must never produce the same encoded form, and every comparison must use the full-width value. For packed blobs, confirm the slice offset matches the documented layout (source first, then destination) [E2](https://bugbountylibrary.com/r/c4%3A2023-09-maia%3AM-11.md). For config codes, test for collisions by constructing distinct pairs with equal output [E3](https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.8.md). Check that off-chain monitoring keys on the same field the contract enforces [E1](https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-1.md).

## Variants seen
- Downcast via assembly: GameType uint32 to uint8, types congruent mod 256 compare equal [E1](https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-1.md)
- Wrong slice of abi.encodePacked(src, dst): reads trailing 20 bytes, caller check always fails [E2](https://bugbountylibrary.com/r/c4%3A2023-09-maia%3AM-11.md)
- Non-injective linear config code: (1,0) and (0,10000) collide, owner frontruns config change [E3](https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.8.md)

## Impact and severity
High. E1 lets a buggy game prove and finalize fraudulent withdrawals on an L1 bridge. E2 breaks all cross-chain messaging. E3 lets a pool owner steal all user stake. Severity rises when the colliding value gates fund release or when the attacker can frontrun the config change.

## Why fixes fail
E1's off-chain watcher comment assumed only respected game types are watched, but the on-chain comparison used the truncated value, so monitoring and enforcement diverged.

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-1.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-09-maia%3AM-11.md
- E3: https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.8.md
