# Funds can be stolen because of incorrect update to `ownerToRollOverQueueIndex` for existing rollovers

In Y2K Carousel, enlistInRollover overwrites ownerToRollOverQueueIndex for existing rollovers, so the notRollingOver check reads the wrong queue item and lets users withdraw locked funds.

- Payout: Contest reward
- Severity: high
- Program: Y2K
- Credited: 0Kage
- Disclosed: 2023-03-06
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/2
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-03-Y2K%3AH-1
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Carousel.sol rollover queue (enlistInRollover / withdraw)
**Root cause:** enlistInRollover unconditionally sets ownerToRollOverQueueIndex[_receiver] = rolloverQueue.length even when updating an existing rollover entry, so the index no longer points to the user's actual queue item.
**Steps:**
1. Call `enlistInRollover(_epochId, _assets, _receiver)` to create a rollover; ownerToRollOverQueueIndex[_receiver] = rolloverQueue.length (last index).
2. Call `enlistInRollover` again for the same receiver; the existing queue item is updated in place at getRolloverIndex(_receiver), but ownerToRollOverQueueIndex is overwritten to rolloverQueue.length.
3. Now getRolloverIndex(_receiver) returns the wrong (last) queue item, so the `notRollingOver` modifier checks a different item's assets/epochId.
4. Call `withdraw(_epochId, _assets, _receiver, _owner)`; the check passes because it inspects the wrong item, allowing withdrawal of assets that should be locked for rollover.
**How found:** Code review of enlistInRollover: noticed the index assignment sits outside the if/else, so it runs even on the update-existing-rollover branch, desynchronizing the index from the actual queue slot.
**Exploitation:** Attacker enlists in a rollover, re-enlists to corrupt their index, then withdraws the assets that were supposed to remain locked for the rollover, extracting funds that should be committed.
**Insight:** When a mapping caches an array index, verify the assignment only happens on push, not on in-place update; a stale/overwritten index silently redirects later modifier checks to the wrong element.
