You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug(genesis): ValidatorManager schema allows zero-address roles and negative voting power bounds #491
The schemaValidatorManager in scripts/genesis/ValidatorManager.ts lacks validation for zero addresses on key governance roles and does not enforce a lower bound on voting power values.
This causes two issues:
Governance Bricking via Zero-Address Initialization: The runtime contract PermissionedValidatorManager.sol explicitly forbids zero addresses in initialize via ZeroOwnerAddress and ZeroPauserAddress. Likewise, Controller.sol and ValidatorRegisterer.sol enforce non-zero addresses via ZeroControllerAddress and ZeroValidatorRegistererAddress. In genesis, writing address(0) into the _owner slot permanently bricks all onlyOwner governance functions (addValidatorRegisterer, configureController, transferOwnership).
Genesis Builder Crash on Negative Voting Power:votingPower and votingPowerLimit use schemaBigInt.max(UINT64_MAX) without .min(0n). Supplying negative values passes schema validation, but crashes the genesis builder during toBytes32() with an unhandled IntegerOutOfRangeError: Number "-1n" is not in safe 256-bit unsigned integer range.
Case-Insensitive Uniqueness: Registerer and controller address sets are checked with case-sensitive equality, failing to catch mixed-casing duplicates that share storage slots.
Proposed Changes
Enforce schemaBigInt.min(0n).max(UINT64_MAX) on both votingPower and votingPowerLimit.
In schemaValidatorManager.superRefine, validate that PermissionedValidatorManager.owner, pauser, validatorRegisterers, and controllers are not the zero address.
Normalize registerer and controller uniqueness checks to be case-insensitive.
Add comprehensive regression tests in tests/unit/validator-manager-genesis-validation.test.ts.
Assignment Request
I have the fix and 12 passing unit tests implemented, verified locally, and signed. Could maintainers ( @ZhiyuCircle@romac@sergio-mena ) please assign this issue to me () so I can open the pull request under the contribution policy?
I checked the current genesis builder and the core validation gaps described here appear real. In particular, the builder writes Ownable._owner and the pauser directly into proxy storage, so the runtime initialize() zero-address checks do not protect this genesis-config path. schemaAddress is format-only, and schemaBigInt.max(UINT64_MAX) still accepts negative bigint values; the later toBytes32 conversion is where those values fail.
A few points that may help make the fix and regression coverage precise:
Test safeParse rejection for zero owner, pauser, validator registerers, and controller addresses, plus negative validators[].votingPower and controllers[].votingPowerLimit. Assert validation fails at the schema boundary rather than later during storage encoding.
Use a non-negative lower bound (0n), not a positive one, unless the contract semantics require otherwise: the current schema permits zero-power entries and separately requires at least one validator with positive power.
Normalize addresses to the same 20-byte identity before duplicate checks. Two strings with different hex casing represent the same EVM address; duplicate controller entries can collide in the address-keyed registration mapping, so test that mixed-case duplicates are rejected before storage generation.
Please describe the threat boundary explicitly: these values come from genesis/operator configuration, so this is an initialization-time misconfiguration/build-validation issue, not a permissionless remote input. The zero-owner case can still brick governance if such a genesis is accepted, but severity should reflect who controls the config and when validation runs.
Thank you @osr21 for the detailed review and guidance!
We completely agree with all four points:
Schema Boundary Rejection: All validations are enforced strictly at the Zod schemaValidatorManager schema boundary via safeParse. Rejections for zero-address roles (owner, pauser, validatorRegisterers, and controllers) and negative bounds fail upfront before storage encoding.
Non-Negative Lower Bound (0n): We enforce schemaBigInt.min(0n).max(UINT64_MAX) on both votingPower and votingPowerLimit, maintaining contract semantics where 0-power entries are valid provided the existing non-empty positive total power requirement is met.
Address Identity Normalization: Addresses are normalized to lower-case 20-byte identity before duplicate checks for both validatorRegisterers and controllers, and we have specific regression tests ensuring mixed-case duplicate entries are caught and rejected.
Threat Boundary Context: The PR description will explicitly frame this as an initialization-time configuration validation / defense-in-depth fix preventing governance bricking and build crashes during genesis compilation.
We have the fix implemented along with 12 regression tests passing locally (12 passing in 7ms) and verified with ESLint.
cc @ZhiyuCircle@romac : The validation gaps are confirmed and aligned above. Could you please assign this issue so we can submit the PR in accordance with the contributing guidelines?
Hi @ZhiyuCircle@romac ,following up on the validation confirmation above with @osr21, we have the complete fix and 12 passing regression tests ready locally. Could you please assign this issue so we can submit the PR in accordance with the contributing guidelines?
Activity
osr21 commentedon Oct 11, 2026
I checked the current genesis builder and the core validation gaps described here appear real. In particular, the builder writes Ownable._owner and the pauser directly into proxy storage, so the runtime initialize() zero-address checks do not protect this genesis-config path. schemaAddress is format-only, and schemaBigInt.max(UINT64_MAX) still accepts negative bigint values; the later toBytes32 conversion is where those values fail.
A few points that may help make the fix and regression coverage precise:
Lesnak1 commentedon Oct 11, 2026
Thank you @osr21 for the detailed review and guidance!
We completely agree with all four points:
schemaValidatorManagerschema boundary viasafeParse. Rejections for zero-address roles (owner,pauser,validatorRegisterers, andcontrollers) and negative bounds fail upfront before storage encoding.0n): We enforceschemaBigInt.min(0n).max(UINT64_MAX)on bothvotingPowerandvotingPowerLimit, maintaining contract semantics where 0-power entries are valid provided the existing non-empty positive total power requirement is met.validatorRegisterersandcontrollers, and we have specific regression tests ensuring mixed-case duplicate entries are caught and rejected.We have the fix implemented along with 12 regression tests passing locally (
12 passing in 7ms) and verified with ESLint.cc @ZhiyuCircle @romac : The validation gaps are confirmed and aligned above. Could you please assign this issue so we can submit the PR in accordance with the contributing guidelines?
Lesnak1 commentedon Oct 13, 2026
Hi @ZhiyuCircle @romac ,following up on the validation confirmation above with @osr21, we have the complete fix and 12 passing regression tests ready locally. Could you please assign this issue so we can submit the PR in accordance with the contributing guidelines?