OpenZeppelin / OpenZeppelin/compact-contracts

N-09: Lack Of Two-Step Ownership Transfer Modules

Open
#814 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

2-low audit
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.