The pool-level initialize omits the two curation gates that live only in Factory.createPool, enabling rogue clones over any valid agreement with any token — a phishing/impersonation surface.
Pools are meant to be created through Factory.createPool, which checks the stake token is allowlisted and that msg.sender owns the agreement.
The implementation is a public minimal-proxy target, and its initialize validates only zero-addresses / expiry / minStake / isAgreementValid — not the token allowlist and not agreement ownership. Anyone can Clones.clone(impl) and initialize over a real valid agreement they do not own, with a non-allowlisted or malicious token, naming themselves owner / moderator / recovery.
Likelihood:
Occurs whenever an attacker clones the public implementation directly and initializes it over a valid registered agreement.
Realized only when a victim is socially engineered into depositing into a pool that is absent from factory.getPoolsByAgreement.
Impact:
Rogue impersonation pool can route a victim's deposits to the attacker's recoveryAddress via a self-flagged CORRUPTED.
Bounded: rogue clones hold only voluntarily-deposited funds; they cannot collide with or touch factory-registered pools (different CREATE2 deployer) or protocol funds.
This shows an attacker cloning the public implementation and initializing a pool over a valid agreement they do not own, using a non-allowlisted token and naming themselves owner/moderator/recovery — none of which initialize rejects.
Restrict initialize to the factory, so the factory's allowlist + ownership gates cannot be bypassed:
(Alternative: re-check allowedStakeToken and IAgreement(agreement).owner() inside initialize itself.)
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
View preliminary resultsAppeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.