Normal behavior:
A faucet contract should allow the operator to maintain and refill the faucet while keeping destructive or high-risk actions (minting, burning, pausing, changing limits, withdrawing) guarded by appropriate governance (multisig, timelock or separated roles). Operator keys used for automation should not simultaneously hold all high-power privileges.
Issue:
A single owner (deployer) account holds multiple high-risk privileges (mintFaucetTokens, burnFaucetTokens, adjustDailyClaimLimit, toggleEthDripPause, refillSepEth, etc.). In addition, burnFaucetTokens contains a problematic implementation that transfers the contract token balance to owner before burning — giving the owner direct ability to extract token balance. This centralization means owner compromise or misuse can immediately disrupt service or extract funds.
Likelihood:
Owner / deployer keys are commonly used for deployment and automation; when a single EOA is used as the owner, compromise or misconfiguration is plausible (high chance during development or insufficient operational controls).
Owner is required for routine operations (refill, parameter change, pause/unpause); every owner action is a high-risk surface that can be triggered by mistake or by a compromised key.
Impact:
Full service disruption — owner can pause ETH drips, set claim limits to 0, or otherwise block legitimate users.
Direct financial loss — due to the burnFaucetTokens logic owner can receive contract token balance and retain the remainder after partial burn; owner-controlled minting can inflate supply.
Trust / governance risk — single-key control undermines decentralization and makes the system fragile to compromise, insider abuse, or operational mistakes.
PoC (high-level steps you can reproduce):
Deploy contract (owner = deployer). Fund contract with tokens and ETH.
As owner, call burnFaucetTokens(amountToBurn) with amountToBurn < balanceOf(address(this)).
Expected result: owner balance increases by balanceOf(address(this)) (full transfer), then _burn reduces owner balance by amountToBurn, leaving owner with (balanceBefore - amountToBurn) tokens extracted from contract.
As owner, call toggleEthDripPause(true) to disable ETH drips; then optionally adjustDailyClaimLimit(0, false) to set low/zero limits; verify claims fail.
As owner, call mintFaucetTokens(address(this), amount) to mint tokens to contract (or to other address depending on to-parameter), or call refillSepEth{value: ...}() to increase contract ETH balance.
Demonstrate that a single owner account can both disable service and extract funds/tokens.
1) Fix burn logic.
Replace current transfer-then-burn with direct burn from contract (or transfer the exact amount if owner should receive tokens).
Rationale: burning from address(this) reduces contract token supply without transferring tokens to owner. If the intended behaviour is to let owner withdraw tokens, implement an explicit withdrawTokens(amount) function protected by governance/multisig (see below).
2) Reduce owner power — adopt role separation and governance.
Replace single EOA onlyOwner operational model with one or more of the following (recommendations in order):
Immediate / pragmatic: Require operator/automation keys to be multisig (e.g., Gnosis Safe) instead of single EOA. Make multisig the owner.
Short-term code change: introduce OPERATOR_ROLE (for low-risk automated ops) and keep critical actions under MANAGER_ROLE or DEFAULT_ADMIN_ROLE protected by a multisig account or timelock. Example pattern (pseudocode):
Best practice: route all admin privilege changes (granting roles, mint/burn beyond small emergency amounts, changing caps) through a timelock or multisig + timelock so community/operators have time to react.
Revoke deployer’s privileged roles after deployment (or make deployer a multisig address).
Add event logging and off-chain alerts for critical changes (pause/unpause, mint, burn, limit changes).
Add explicit tests asserting that only expected roles can perform specific actions (regression test).
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.