Summary
Summary: The uninstallModule
function emits the ModuleUninstalled
event before actually uninstalling the module. This premature emission can lead to inconsistencies between the event logs and the actual contract state, potentially causing issues for systems relying on these events.
Vulnerability Details
In the uninstallModule
function, the ModuleUninstalled
event is emitted before the actual uninstallation of the module takes place. This creates a discrepancy between the event log and the actual state of the contract.
function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable onlyEntryPointOrSelf {
emit ModuleUninstalled(moduleTypeId, module);
if (moduleTypeId == MODULE_TYPE_VALIDATOR) {
_uninstallValidator(module, deInitData);
} else if (moduleTypeId == MODULE_TYPE_EXECUTOR) {
_uninstallExecutor(module, deInitData);
}
}
https://github.com/Cyfrin/2024-07-biconomy/blob/9590f25cd63f7ad2c54feb618036984774f3879d/contracts/Nexus.sol#L205
Impact
Incorrect off-chain tracking of contract state.
Potential exploitation in systems relying on these events for critical operations.
Tools Used
Manual Review
Recommendations
Reorder the function to emit the event after the module uninstallation:
function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable onlyEntryPointOrSelf {
require(IModule(module).isModuleType(moduleTypeId), MismatchModuleTypeId(moduleTypeId));
require(_isModuleInstalled(moduleTypeId, module, deInitData), ModuleNotInstalled(moduleTypeId, module));
if (moduleTypeId == MODULE_TYPE_VALIDATOR) {
_uninstallValidator(module, deInitData);
} else if (moduleTypeId == MODULE_TYPE_EXECUTOR) {
_uninstallExecutor(module, deInitData);
} else if (moduleTypeId == MODULE_TYPE_FALLBACK) {
_uninstallFallbackHandler(module, deInitData);
} else if (moduleTypeId == MODULE_TYPE_HOOK) {
_uninstallHook(module, deInitData);
}
emit ModuleUninstalled(moduleTypeId, module);
}