OpenZeppelin / OpenZeppelin/compact-contracts
N-09: Lack Of Two-Step Ownership Transfer Modules
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 55
- Forks
- 29
- Avg merge
- 5d 7h
- Merged PRs (30d)
- 25
Description
N-06 Lack Of Two-Step Ownership Transfer Modules
Severity: Note
Source: Midnight Foundation #02 — OpenZeppelin Compact Contracts Audit, Release 0.3.0-alpha.1 (2026-08-18)
ZOwnablePK implements ownership by storing an _ownerCommitment and requiring privileged circuits to call assertOnlyOwner. This function recomputes an owner identifier from ownPublicKey() and the witness wit_secretNonce(), and compares it against that commitment. A valid identifier is therefore a hash preimage, since _computeOwnerId returns persistentHash over the public key and the nonce.
Ownership transfer is a single step. transferOwnership accepts any newOwnerId other than the type default and commits it, with no step in which the recipient demonstrates that a preimage exists. For an arbitrary 32-byte value, no such preimage is findable, so once this value is committed, no caller can satisfy assertOnlyOwner and every owner-gated circuit becomes permanently unreachable. This includes the two circuits that might otherwise recover the situation, since a further transferOwnership and renounceOwnership both begin by calling assertOnlyOwner. Similarly, Ownable.compact too implements the single-step ownership transfer.
Consider implementing a two-step transfer module in which transferOwnership records a pending identifier and a separate acceptance circuit requires the recipient to prove knowledge of a public key and secret nonce reproducing it before _ownerCommitment is updated, similar to the Ownable and Ownable2Step contracts of the OpenZeppelin Solidity Library.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading contracts/src/access/ZOwnablePK.compact, especially transferOwnership, assertOnlyOwner, and the ownership-recovery circuits, then compare the corresponding behavior in Ownable.compact. Review the linked Solidity Ownable2Step contracts for the intended two-step flow. Done means both Compact ownership modules support pending transfers and recipient acceptance with proof of the required preimage.
Written by the indexing model from the issue text.
Assessment
- Domain
- authorization, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100