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

Missing expiry upper bound validation in factory

Author Revealed upon completion

Description

createPool() checks expiry < block.timestamp + _MIN_EXPIRY_LEAD (30 days minimum) but does NOT check expiry > type(uint32).max. The pool's initialize() does perform this check (Pool:197: if (expiry_ > type(uint32).max) revert ExpiryTooFar()), but it runs after cloneDeterministic() has already deployed the clone at Factory:87.

Factory:78 if (expiry < block.timestamp + _MIN_EXPIRY_LEAD) revert ExpiryTooSoon();
// MISSING: if (expiry > type(uint32).max) revert ExpiryTooFar();
Factory:87 pool = Clones.cloneDeterministic(poolImplementation, salt); // clone deployed first
Factory:90 IConfidencePool(pool).initialize(... expiry ...); // uint32 check happens HERE, after clone

Risk

Likelihood: Very low. type(uint32).max ≈ 4.3 billion (year 2106). Current timestamps are ~1.75 billion. Only a manual input error or fuzz test would trigger this.

Impact: Low. If triggered, the clone is deployed (~50k gas) but initialize() reverts, leaving an orphaned clone at a deterministic CREATE2 address. The salt is consumed — the same agreement-index pair can never create a pool again.

Mitigation

Add the upper bound check in createPool() before cloneDeterministic():

if (expiry < block.timestamp + _MIN_EXPIRY_LEAD) revert ExpiryTooSoon();
+if (expiry > type(uint32).max) revert ExpiryTooFar();

Support

FAQs

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

Give us feedback!