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.
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.originIsRootreads the transaction origin, not the caller (upstream it isself.origin == Origin::Rootfrompolkadot-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 RootRevive.callinto any Asset Hub contract is enough.That grants the whitelist's ten
onlyGovernancefunctions,setShortNamesEnabled, the whole PoP issuance surface, andregisterReserved's Root branch, which skips bothisGrantedToandconsumeand passes0as 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:290states 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_originis false across a UUPS delegatecall frame, so it returns false even on a direct one-hop Root dispatch. That is whyoriginIsRootwas 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:290does block R1: shipping a guarantee we know to be false is worse than shipping the defect.