Missing access control on createAccount enables unlimited proxy-deployment spam
Description
The ManagementAccountFactory::createAccount function lacks access control, unlike other administrative functions in the factory:
!function createAccount(address owner_) external returns (address account) {
bytes memory initData = abi.encodeWithSelector(ManagementAccount.initialize.selector, owner_, address(this));
! account = address(new ERC1967Proxy(implementation, initData));
emit AccountCreated(account, owner_);
}This allows anyone to create unlimited accounts for arbitrary addresses without restriction.
Impact
Without access control, attackers can create unlimited accounts for arbitrary addresses, enabling spam and griefing attacks.
Spam attacks. Unlimited account creation can overwhelm backend infrastructure tracking accounts, causing database bloat, increased costs, and potential denial-of-service on indexing services.
Griefing attacks. Accounts can be created for arbitrary addresses without consent, associating unwanted Hyperbeat Pay accounts with user addresses.
Recommendations
Restrict createAccount to an authorized role, consistent with other factory administrative functions:
-function createAccount(address owner_) external returns (address account) {
+function createAccount(address owner_) external onlyRole(IMPLEMENTATION_ADMIN_ROLE) returns (address account) {
bytes memory initData = abi.encodeWithSelector(ManagementAccount.initialize.selector, owner_, address(this));
account = address(new ERC1967Proxy(implementation, initData));
emit AccountCreated(account, owner_);
}This allows the backend to enforce validation, rate limiting, and any necessary authorization checks before account deployment.
Remediation
This issue has been acknowledged by Hyperbeat, and a fix was implemented in commit b0a7e5e9↗.