Origins
The origin of a call tells a dispatchable function where the call has come from. Origins are a way to implement access controls in the system.
There are three types of origins that can used in the runtime:
#![allow(unused)] fn main() { pub enum RawOrigin<AccountId> { Root, Signed(AccountId), None, } }
Outside of the out-of-box origins, custom origins can also be created that are catered to a specific runtime. The primary use case for custom origins is to configure privileged access to dispatch calls in the runtime, outside of RawOrigin::Root
.
Using privileged origins, like RawOrigin::Root
or custom origins, can lead to access control violations if not used correctly. It is a common error to use ensure_signed
in place of ensure_root
which would allow any user to bypass the access control placed by using ensure_root
.
Example
In the pallet-bad-origin
pallet, there is a set_important_val
function that should be only callable by the ForceOrigin
custom origin type. This custom origin allows the pallet to specify that only a specific account can call set_important_val
.
#![allow(unused)] fn main() { #[pallet::call] impl<T:Config> Pallet<T> { /// Set the important val /// Should be only callable by ForceOrigin #[pallet::weight(10_000)] pub fn set_important_val( origin: OriginFor<T>, new_val: u64 ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; // Change to new value <ImportantVal<T>>::put(new_val); // Emit event Self::deposit_event(Event::ImportantValSet(sender, new_val)); Ok(().into()) } } }
However, the set_important_val
is using ensure_signed
; this allows any account to set ImportantVal
. To allow only the ForceOrigin
to call set_important_val
the following change can be made:
#![allow(unused)] fn main() { T::ForceOrigin::ensure_origin(origin.clone())?; let sender = ensure_signed(origin)?; }
Mitigations
- Ensure that the correct access controls are placed on privileged functions.
- Develop user documentation on all risks associated with the system, including those associated with privileged users.
- A thorough suite of unit tests that validates access controls is crucial.
References
- https://docs.substrate.io/main-docs/build/origins/
- https://docs.substrate.io/tutorials/build-application-logic/specify-the-origin-for-a-call/
- https://paritytech.github.io/substrate/master/pallet_sudo/index.html#
- https://paritytech.github.io/substrate/master/pallet_democracy/index.html