# Possibility for multiple Connector or Merkle chips

OpenVM verifier accepted duplicate AIR ids in per_air, letting a malicious prover add a second Connector/Merkle chip to fake PC or memory state.

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

**Target:** zkVM proof verifier (Rust verifier / recursive verifier)
**Root cause:** Verifier only checks that required AIR types appear at fixed indices (0th Program, 1st Connector, 3rd Merkle) but never enforces uniqueness of air_ids across per_air, so a prover can append duplicate ConnectorChip/MemoryMerkleChip instances.
**Steps:**
1. Craft a Proof whose per_air contains the honest ConnectorChip plus an extra ConnectorChip with the same air_id.
2. Place the fake chip first so get_connector_pvs reads its public values while the verifier ignores the honest chip's PVs.
3. Have the fake chip send/receive identical initial PC/timestamp so the bus constraints still balance.
4. Verifier accepts the proof and reads a program counter that did not advance.
5. Analogous attack with MemoryMerkleChip plus extra PersistentBoundaryChip rows to claim memory unchanged.
**How found:** Code review of proof.rs Proof struct and recursive verifier mod.rs: noticed per_air is prover-controlled and assert_required_air_for_app_vm_present only checks positional AIR types, while get_connector_pvs/get_memory_pvs read fixed indices, implying duplicates are unchecked.
**Exploitation:** Malicious prover constructs a proof with duplicated chip instances; because bus send/receive data is identical the bus check passes, but the verifier only inspects PVs of the first chip of each type, so it accepts a false state transition (e.g. skipped memory write or unadvanced PC).
**Escalation:** Chaining across segments with continuations enabled lets the prover skip arbitrary memory writes by isolating them in their own segment and asserting memory unchanged.
**Insight:** In zkVM/STARK verifiers, positional checks on AIR ordering are not enough: audit whether air_id uniqueness is enforced, since duplicate instances of singleton chips (connector, merkle, boundary) can desync public values from bus constraints.
