# Past state query results are susceptible to manipulation due to multiple states with same block number

Paladin hPAL history arrays allow duplicate fromBlock entries, so binary-search past-state queries can be manipulated to return a chosen lock/delegate history.

- Payout: Audit contest
- Severity: medium
- Program: Paladin
- Found by: rayn
- Disclosed: 2022-05-10
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-03-paladin-findings/issues/20
- Library page: https://bugbountylibrary.com/r/c4%3A2022-03-paladin%3AM-05
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:accounting-error

**Target:** HolyPaladinToken.sol history checkpoint query functions
**Root cause:** _lock and related writers push new UserLock/TotalLock/DelegateCheckpoint entries even when fromBlock equals the previous entry's block, creating a one-to-many block-to-entry mapping that binary search resolves ambiguously.
**Steps:**
1. Read _getPastLock/getPastTotalLock/_getPastDelegate binary search over userLocks/totalLocks/delegateCheckpoints.
2. Observe _lock pushes a new UserLock with safe32(block.number) regardless of prior entry's fromBlock.
3. Within one block, perform multiple lock updates (increase amount/duration) to create several entries sharing the same fromBlock.
4. Craft entry count/ordering so binary search lands on the entry whose values the attacker wants exposed.
5. Query the public past-state function at that block to receive the manipulated history.
**How found:** Code review of history-keeping structures: noticed 3 of 4 state types permit duplicate fromBlock while checkpoint dedupes, then traced binary-search query functions to show ambiguity and attacker-controllable selection.
**Exploitation:** Attacker with lock/delegate state performs multiple same-block updates to control array layout, then public history queries return attacker-chosen values instead of true past state; no direct asset loss.
**Insight:** When auditing checkpoint/binary-search history patterns, check whether writers dedupe on block number; any push-without-merge on same block turns a 'past state' oracle into attacker-influenced data for anything consuming it (voting, rewards, delegation).
