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]: Root-origin gates are transaction-wide, so any contract a Root call reaches inherits DotNS governance #300
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
callerIsRoot() was not usable here because of a pallet-revive bug, paritytech/polkadot-sdk#13412. Behind a UUPS proxy it returns false even for a direct Root dispatch, which is why originIsRoot() was chosen. The same bug makes it return true in a contract reached through a delegate call followed by a regular call, so any contract that a Root dispatch reaches can pass a callerIsRoot() check in another contract.
The fix is paritytech/polkadot-sdk#13413. Once it is live on Asset Hub, callerIsRoot() is true only in the contract that Root dispatched to, including behind its proxy, and the four gates can switch from originIsRoot() to callerIsRoot() with an upgrade of each contract.
PR #302 routes Root through DotnsRootGateway, which checks callerIsRoot(). Until #13413 ships, a Root-dispatched contract can pass that check with a delegate call followed by a regular call, so the gateway does not close this issue. Once #13413 ships, the gateway is no longer needed.
Update: the pallet-revive fix, paritytech/polkadot-sdk#13413, is merged on polkadot-sdk master (not backported), and paritytech/polkadot-sdk#13412 is closed. It reaches Asset Hub with the first polkadot-sdk release that includes it and the Asset Hub runtime upgrade that picks it up. From then on, the four gates can switch from originIsRoot() to callerIsRoot() with an upgrade of each contract, and the DotnsRootGateway from #302 is no longer needed.
Activity
re-gius commentedon Sep 25, 2026
PR #302 needs further discussion, so this has been moved out of the scope for R1 and will be addressed for R2 - removing from milestone
re-gius commentedon Oct 8, 2026
Update: the pallet-revive fix, paritytech/polkadot-sdk#13413, is merged on polkadot-sdk
master(not backported), and paritytech/polkadot-sdk#13412 is closed. It reaches Asset Hub with the first polkadot-sdk release that includes it and the Asset Hub runtime upgrade that picks it up. From then on, the four gates can switch fromoriginIsRoot()tocallerIsRoot()with an upgrade of each contract, and theDotnsRootGatewayfrom #302 is no longer needed.valentyna-kozlova commentedon Oct 9, 2026
Decided on 9 Oct meeting that this should be done.