Summary
InitNexus
implementation configures the registry after attempting to install validators, executors, hooks, and fallback handlers. Account initialization process can incorrectly allow modules to be installed without the appropriate attestations if the user intends to use the registry feature. The issue arises because the registry is configured after the modules are installed, resulting in the registry checks being bypassed.
The root cause of the issue lies in the sequence of operations within the `initializeAccount` function and the `initNexus` function. The registry configuration is performed last in `initNexus`, but `_installValidator` and other module installation functions rely on the registry check. As a result, modules can be installed without appropriate attestations because the registry is configured too late.
Vulnerability Details
function initNexus(
BootstrapConfig[] calldata validators,
BootstrapConfig[] calldata executors,
BootstrapConfig calldata hook,
BootstrapConfig[] calldata fallbacks,
IERC7484 registry,
address[] calldata attesters,
uint8 threshold
) external {
for (uint256 i = 0; i < validators.length; i++) {
_installValidator(validators[i].module, validators[i].data);
}
for (uint256 i = 0; i < executors.length; i++) {
if (executors[i].module == address(0)) continue;
_installExecutor(executors[i].module, executors[i].data);
}
if (hook.module != address(0)) {
_installHook(hook.module, hook.data);
}
for (uint256 i = 0; i < fallbacks.length; i++) {
if (fallbacks[i].module == address(0)) continue;
_installFallbackHandler(fallbacks[i].module, fallbacks[i].data);
}
_configureRegistry(registry, attesters, threshold);
}
. **Validator Installation**:
- The `_installValidator` function is called during the initialization of validators.
- It checks the registry via the `withRegistry` modifier before adding the validator.
- Since the registry is not yet configured, `_checkRegistry` will assume no registery is used and continue execution.
modifier withRegistry(address module, uint256 moduleType) {
_checkRegistry(module, moduleType);
_;
}
function _checkRegistry(address module, uint256 moduleType) internal view {
IERC7484 moduleRegistry = registry;
if (address(moduleRegistry) != address(0)) {
moduleRegistry.check(module, moduleType);
}
}
function _installValidator(address validator, bytes calldata data) internal virtual withRegistry(validator, MODULE_TYPE\\\_VALIDATOR)
if (!IValidator(validator).isModuleType(MODULE_TYPE_VALIDATOR)) revert MismatchModuleTypeId(MODULE_TYPE_VALIDATOR);
_getAccountStorage().validators.push(validator);
IValidator(validator).onInstall(data);
}
**Order of Operations**: In initNexus
, the _configureRegistry
function is called after _installValidator
. This means that when `_installValidator` is executed, the registry is not yet set.
- **Registry Check**: Since the registry configuration occurs after the modules are installed, the registry check is bypassed the registry is not set up first.
Impact
Modules can be installed without the appropriate attestations, compromising the security guarantees provided by the registry.
Tool Used
Manual Review
Recommendations
Ensure the registry is configured before installing any validators, executors, hooks, or fallback handlers.
function initNexus(
BootstrapConfig[] calldata validators,
BootstrapConfig[] calldata executors,
BootstrapConfig calldata hook,
BootstrapConfig[] calldata fallbacks,
IERC7484 registry,
address[] calldata attesters,
uint8 threshold
) external {
_configureRegistry(registry, attesters, threshold);
for (uint256 i = 0; i < validators.length; i++) {
_installValidator(validators[i].module, validators[i].data);
}
for (uint256 i = 0; i < executors.length; i++) {
if (executors[i].module == address(0)) continue;
_installExecutor(executors[i].module, executors[i].data);
}
if (hook.module != address(0)) {
_installHook(hook.module, hook.data);
}
for (uint256 i = 0; i < fallbacks.length; i++) {
if (fallbacks[i].module == address(0)) continue;
_installFallbackHandler(fallbacks[i].module, fallbacks[i].data);
}
}