Skip to content

[Bug]: Root-origin gates are transaction-wide, so any contract a Root call reaches inherits DotNS governance #300

Description

@re-gius

Component

Other

Priority

P1

What happened?

Four contracts gate governance on SystemUtils.originIsRoot(): DotnsRegistrarController.sol:296, DotnsPopController.sol:936, PopRules.sol:90, DotnsNameWhitelist.sol:109.

originIsRoot reads the transaction origin, not the caller (upstream it is self.origin == Origin::Root from polkadot-sdk substrate/frame/revive/src/exec.rs:2431), with no frame comparison. The authority is therefore ambient for the whole call stack, so any code reached during a Root transaction holds full DotNS governance without holding any DotNS key. The trigger need not involve DotNS: any Root Revive.call into any Asset Hub contract is enough.

That grants the whitelist's ten onlyGovernance functions, setShortNamesEnabled, the whole PoP issuance surface, and registerReserved's Root branch, which skips both isGrantedTo and consume and passes 0 as the charge — any available label to any owner for free, including the 3-to-8 band the priced path is closed out of. PoP names are soulbound, so issuance is permanent without a registrar upgrade.

Expected behavior

Governance authority should require the Root dispatch to be aimed at DotNS, not merely that a Root transaction is somewhere on the stack.

DEPLOYMENTS.md:290 states the stronger guarantee today: "No signed account can do any of them, the contract owner included" and "no single key can grant a name; a grant costs a referendum", and neither holds while the gate is transaction-wide.

Reproduction

No path inside DotNS produces the trigger; it needs a Root dispatch reaching code governance does not control.

Additional context

Swapping to callerIsRoot() does not build: caller_is_origin is false across a UUPS delegatecall frame, so it returns false even on a direct one-hop Root dispatch. That is why originIsRoot was chosen, and upstream designates it for the proxy pattern.

R1: the code fix is not a launch blocker, since all four contracts are UUPS and the gate can be tightened by owner upgrade. Correcting DEPLOYMENTS.md:290 does block R1: shipping a guarantee we know to be false is worse than shipping the defect.

Activity

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

Metadata

Metadata

Assignees

Labels

P1Secondary PrioritysecurityRelated to securitytype: bugBug report

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions