# Inserted register reads at arbitrary timestamps

Unconstrained dummy ALU rows let a malicious OpenVM prover insert register reads at arbitrary timestamps, chaining with timestamp overflow to skip any register write.

- Payout: Contest reward
- Severity: high
- Program: OpenVM
- Credited: georg
- Disclosed: 2025-03-24
- Write-up quality: 9/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_openvm_january2025.pdf#3.1.3
- Library page: https://bugbountylibrary.com/r/cantina%3Aopenvm_january2025%3A3.1.3
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:cantina sev:high tech:rust technique:chained technique:source-review vuln:business-logic vuln:precision-loss

**Target:** zkVM ALU adapter AIR / memory argument
**Root cause:** In Rv32BaseAluAdapterAir::evaluate, rs2_as can be 1 while is_valid=0, leaving timestamp, address and value of the dummy row unconstrained since the execution bridge is disabled.
**Steps:**
1. Observe rs2_as toggles a memory read but is only constrained via execution bridge, which is off when is_valid=0.
2. Craft 4 dummy ALU rows with is_valid=0, rs2_as=1, timestamps spaced by 2^29: `42, 42+2^29, 42+2*2^29, 42+3*2^29`.
3. Set pointer/address_space/data freely (e.g. pointer=24, data=240) and generate read aux cols via `generate_read_aux`.
4. Timestamps overflow field p=2^31-2^27+1 in 4 accesses, breaking the strict-less-than check and forming a loop in the memory graph.
5. Wire the second read to receive the first read's value, bypassing the intervening write; checks (1) bus and (2) timestamp ordering still pass.
6. Apply PoC diff removing debug_asserts and adding mutate_dummy_row, run Fibonacci example to confirm loop insertion.
**How found:** Code review of Rv32BaseAluAdapterAir::evaluate: noticed rs2_as is only constrained through the execution bridge, which is disabled when is_valid=0, leaving dummy-row cells unconstrained; then reasoned about the memory argument graph and timestamp overflow to weaponize it.
**Exploitation:** Malicious prover pads ALU chip with 4 dummy rows carrying crafted timestamps and read records, creating a cyclic memory-access graph that skips a chosen register write, altering program output/side effects (e.g. skipping an account balance update to double-spend).
**Escalation:** Chains with the separate 'timestamp can overflow' finding to make the loop feasible; affects memory accesses of any chip interacting with registers, not just ALU.
**Insight:** In zkVM AIRs, flags that gate memory operations must be constrained independently of is_valid; check whether padding/dummy rows leave bus-relevant columns (timestamp, address, value) free, and whether timestamp ordering checks can be defeated by field overflow to create cycles in the memory permutation graph.
