F-2025-0008·centralization-risk

Single owner as sole point of failure enables protocol compromise

Fixedlotterypixel-lotterychainlink-vrf
TL;DR

All admin functions sit behind a single Ownable owner. If the EOA or multisig is compromised, an attacker can redirect funds, manipulate parameters, and control the protocol with no granular role separation.

Severity
LOW
Impact
HIGH
Likelihood
LOW
Method
MManual review
CAT.
Complexity
HIGH
Exploitability
LOW
02Section · Description

Description

The protocol implements a single owner model using OpenZeppelin's Ownable pattern, creating a critical single point of failure despite having multisig infrastructure available. All administrative functions, including those that can redirect protocol funds or manipulate economic parameters, are controlled by a single onlyOwner modifier.

While the documentation indicates the owner is intended to be a multisig wallet, the current implementation does not enforce or leverage multisig capabilities at the smart contract level. This creates an unnecessary centralization risk where:

  • The compromise of the owner account (whether EOA or multisig) provides complete protocol control
  • No granular access control exists for different risk levels of operations
  • The multisig infrastructure is underutilized, providing no additional security layers

The risk is compounded by the fact that owner-controlled functions can:

  • Redirect all protocol revenue by changing distribution addresses
  • Manipulate economic parameters like pricing
  • Control all aspects of protocol operation without any checks or balances
03Section · Recommendation

Recommendation

Leverage the existing multisig infrastructure by implementing role-based access control that utilizes multisig capabilities:

  1. Replace single owner with role-based system:
solidity
contract PixelLotteryAPE is AccessControl {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
}
  1. Assign different multisig wallets to different roles:

    • ADMIN_ROLE: High-security multisig for fund-affecting functions
    • OPERATOR_ROLE: Operational multisig for routine parameter changes
  2. Implement role-specific function access:

solidity
function enqueueConfigChange(ConfigParam param, uint256 value) external {
if (_isCriticalParameter(param)) {
require(hasRole(ADMIN_ROLE, msg.sender), "Admin role required");
} else {
require(hasRole(OPERATOR_ROLE, msg.sender), "Operator role required");
}
// ... function logic
}
function _isCriticalParameter(ConfigParam param) private pure returns (bool) {
return param == ConfigParam.TEAM_CONTRACT_ADDRESS ||
param == ConfigParam.FOUNDATION_ADDRESS ||
param == ConfigParam.SOCIAL_PROJECTS_ADDRESS;
}
  1. Utilize multisig threshold differences:
    • Configure admin multisig with higher threshold (e.g., 4/5 signatures)
    • Configure operator multisig with lower threshold (e.g., 2/3 signatures)

This approach eliminates the single point of failure while making practical use of the available multisig infrastructure, providing defense in depth without adding significant operational overhead.

04Section · Resolution

Resolution

Golden Grid: Confirmed. As agreed, we will use only AccessControl on lottery contract to not over-complicate things.

Zealynx: Fixed. Discussed and agreed about the solution proposed by dev team.

Status
Fixed
F-2025-0008

oog
zealynx

Smart Contract Security Digest

Monthly exploit breakdowns, audit checklists, and DeFi security research — straight to your inbox

© 2026 Zealynx