Skip to content

fix(shared): compare ownership nominations against the current owner - #579

Open
bb111189 wants to merge 2 commits into
smartcontractkit:developfrom
bb111189:codex/fix-ownable-constructor-owner-check
Open

bb111189 wants to merge 2 commits into
smartcontractkit:developfrom
bb111189:codex/fix-ownable-constructor-owner-check

Conversation

@bb111189

Copy link
Copy Markdown

Summary

Compare ownership nominations against s_owner, rather than msg.sender, in Ownable2Step._transferOwnership.

Constructor edge case

The constructor accepts an initial owner and an optional pending owner. It sets s_owner = newOwner before calling _transferOwnership(pendingOwner). At that point, msg.sender is the deployer (or factory), not necessarily the initial owner.

For distinct addresses D (deployer) and O (initial owner):

Constructor arguments Current behavior Expected behavior
newOwner = O, pendingOwner = D Reverts with CannotTransferToSelf Deploy successfully; O remains owner until D accepts
newOwner = O, pendingOwner = O Allows nomination of the current owner Revert with CannotTransferToSelf

This is a constructor-validation correctness issue for specific arguments, not a demonstrated ownership-takeover vulnerability.

Fix and compatibility

  • Compare the nominee with the actual stored owner.
  • Normal owner-only transfers retain their existing behavior because their caller is the current owner.
  • Zero-address cancellation and zero pending-owner initialization remain supported.
  • No ABI or storage-layout changes.
  • This source change does not modify already-deployed contracts.
  • Ownable2StepMsgSender initializes with a zero pending owner and is unaffected by the constructor edge case.

Tests

Added deterministic regression tests for both constructor cases, a normal constructor nomination/acceptance test, a fuzz test over deployer/owner/nominee combinations, and a zero-address cancellation regression.

Before the fix, the added tests reproduce three failures (including the fuzz counterexample). After the fix:

  • Focused ownership suite: 13 passed, with 10,000 fuzz runs.
  • Full shared-contract suite: 214 passed, 0 failed, 0 skipped.
  • Shared gas snapshot regenerated and checked.
  • Formatting, focused source/test Solhint, and git diff --check passed. The test file is normally excluded by the repository's test lint ignore list; it was additionally linted explicitly using --ignore-path /dev/null.

Validation used Foundry v1.7.1, the shared profile, Solidity 0.8.26, Paris EVM, and 1,000,000 optimizer runs. Other product suites were not run locally; upstream CI remains necessary.

Includes a patch changeset and updated shared gas snapshot.

@bb111189
bb111189 requested a review from a team as a code owner October 22, 2026 10:31

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant