# swapValidatorDetails incorrectly writes keys to memory, resulting in permanently locked beacon chain deposits

swapValidatorDetails mstore ordering zeroes bytes 16-31 of BLS pubkeys, so swapped validators get malformed keys and allocated ETH is permanently locked in the beacon deposit contract.

- Payout: Contest reward
- Severity: high
- Program: Rio Network Core Protocol
- Credited: 0xkaden
- Disclosed: 2024-02-14
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2024-02-rio-network-core-protocol-judging/issues/84
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-rio-network-core-protocol%3AH-5
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:business-logic

**Target:** ValidatorDetails.sol assembly key-swap in RioLRTOperatorRegistry
**Root cause:** Second mstore at offset 0x30 with shr(128,_part2) zeroes the leftmost 128 bits, overwriting bytes 16..31 written by the first mstore at 0x20, corrupting the 48-byte BLS key in memory.
**Steps:**
1. Call reportOutOfOrderValidatorExits triggering VALIDATOR_DETAILS_POSITION.swapValidatorDetails(operatorId, fromIndex, validators.exited, validatorCount).
2. In swapValidatorDetails, key1/key2 are `new bytes(48)`; sload keyOffset1 and keyOffset1+1 into _part1/_part2.
3. Execute `mstore(add(key1,0x20),_part1)` then `mstore(add(key1,0x30),shr(128,_part2))` — the second store zeroes bytes 16..31.
4. Verify in chisel with `!memdump`: key becomes `0x95cf...a9390000...0000` + `0x8af9...b78d`.
5. Later allocateETHDeposits loads corrupted pubKeyBatch and stakeETH passes it to beacon DepositContract.deposit.
**How found:** Manual review of the assembly key-loading in swapValidatorDetails; noticed the shr(128) mstore at 0x30 overlaps the 0x20 store, then reproduced the zeroed middle bytes in chisel via !memdump.
**Exploitation:** Any out-of-order validator exit triggers the swap; subsequent deposit allocations use the corrupted pubkeys, sending ETH to beacon chain keys with no known private key, permanently locking funds.
**Insight:** When copying >32-byte values from storage to memory in assembly, check mstore offset arithmetic: a shr(128) store at +0x30 overlaps the +0x20 store and zeroes bytes 16..31 — verify with chisel !memdump.
