FoundrySolidityLayer 2
7.25 ETH
Submission Details
Impact: medium
Likelihood: medium

Factory allows invalid pool initialization

Author Revealed upon completion

Root + Impact

Description

  • The factory should create pools only with valid, protocol-compliant parameters so each new pool starts in a safe and usable state.

  • The issue is that ConfidencePoolFactory.sol can be abused or misused through weak input validation during createPool, which may deploy a pool with invalid configuration and break later deposits or settlement.

// Root cause in the codebase with @> marks to highlight the relevant section
function createPool(
address stakeToken,
address sponsor,
address moderator,
uint256 expiry,
bytes32 agreementId
) external returns (address pool) {
// @> missing strict validation on pool parameters
// @> bad token, zero addresses, or invalid expiry can pass through
pool = _deployClone();
// @> pool is initialized with unchecked inputs
ConfidencePool(pool).initialize(
stakeToken,
sponsor,
moderator,
expiry,
agreementId
);
}

Risk

Likelihood:

  • The bug is reached on every pool creation, so malformed configuration can be introduced at the protocol entry point.

  • Factory functions are commonly public, making invalid inputs easy to submit during normal use or via attacker-crafted calls.

Impact:

  • A pool can be deployed in a broken state, causing failed deposits, failed settlement, or locked funds.

  • The issue affects all users of that pool and can repeat across multiple deployments.

Proof of Concept

// Conceptual PoC:
// 1. Call createPool() with a zero moderator or unsupported stake token.
// 2. Factory deploys and initializes the pool anyway.
// 3. Later user actions fail or the pool behaves incorrectly.

Recommended Mitigation

- remove this code
+ add this code
function createPool(
address stakeToken,
address sponsor,
address moderator,
uint256 expiry,
bytes32 agreementId
) external returns (address pool) {
+ require(stakeToken != address(0), "invalid token");
+ require(sponsor != address(0), "invalid sponsor");
+ require(moderator != address(0), "invalid moderator");
+ require(expiry > block.timestamp, "invalid expiry");
+ require(isSupportedToken(stakeToken), "unsupported token");
+ require(!agreementExists(agreementId), "duplicate agreement");
pool = _deployClone();
ConfidencePool(pool).initialize(
stakeToken,
sponsor,
moderator,
expiry,
agreementId
);
}

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!