# Proposal id collision in governance

Proposal ids compared, summed or deduplicated without binding to lifecycle or uniqueness

_Area: Smart contract access control and control flow. Seen in 2 disclosed reports; latest 2022-12-21. Updated 2026-10-23._

## How it works
Governance code treats a proposal id as a plain value: it compares ids, sums budgets per id, or checks membership in a winning set. The broken assumption is that each id appears once and refers to one live proposal. When ids are not bound to uniqueness or lifecycle, the same id can be counted twice, compared against itself, or reused, so checks that look like they enforce quorum, budget or approval are satisfied trivially or inflated. The result is that legitimate proposals are blocked, or execution paths run when they should not.

## Where it shows up
- Slate/committee selection loops that sum per-item budgets or votes without a duplicate check [E2](https://bugbountylibrary.com/r/sherlock%3A2023-01-ajna%3AH-6.md)
- Winning-set checks that test membership only, not distinctness [E2](https://bugbountylibrary.com/r/sherlock%3A2023-01-ajna%3AH-6.md)
- Paired id parameters (old/new, from/to) with no requirement they differ [E3](https://bugbountylibrary.com/r/c4%3A2021-04-vader%3AH-04.md)
- Comparison-based approval or minority checks that can compare a proposal to itself [E3](https://bugbountylibrary.com/r/c4%3A2021-04-vader%3AH-04.md)
- Permission sets where one role can cancel everything and another alone can propose, with no recovery path [E1](https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-13.md)

## How to review
The invariant: every id used in a comparison, sum, dedup or membership test must refer to exactly one distinct, live proposal, and paired ids must be distinct. Check that slate construction rejects duplicates before summing budgets, that success checks require distinct membership, and that cancel/compare paths reject identical ids. For governance roles, map each actor's permissions and ask which single compromise is unrecoverable; asymmetric cancel-vs-propose rights between two roles is a deadlock vector [E1](https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-13.md).

## Variants seen
- Duplicate ids in a slate inflate the budget total and block a legitimate proposal from funding/execution [E2](https://bugbountylibrary.com/r/sherlock%3A2023-01-ajna%3AH-6.md)
- Self-comparison of old and new ids makes a minority check pass, allowing anyone to cancel [E3](https://bugbountylibrary.com/r/c4%3A2021-04-vader%3AH-04.md)
- Asymmetric cancel/propose permissions between securityCouncil and owner deadlock upgrades [E1](https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-13.md)

## Impact and severity
Blocked or hijacked governance execution: proposals cannot be funded or executed [E2](https://bugbountylibrary.com/r/sherlock%3A2023-01-ajna%3AH-6.md), any proposal can be cancelled [E3](https://bugbountylibrary.com/r/c4%3A2021-04-vader%3AH-04.md), or upgrades are permanently blocked with no recovery [E1](https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-13.md). Severity is high because governance is the control plane; a single unrecoverable path or a trivially satisfied check removes the ability to correct the system.

## Why fixes fail
Evidence does not show incomplete or regressed fixes.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-13.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2023-01-ajna%3AH-6.md
- E3: https://bugbountylibrary.com/r/c4%3A2021-04-vader%3AH-04.md
