Due to the lack of validation between the proxy
parameter and the remaining parameters passed to the ProxyFactory::distributeByOwner
function, it is possible to call _distribute
on a non-expired contest.
The function ProxyFactory::distributeByOwner
serves the purpose of enabling the owner to distribute funds that are were sent to the distributor proxies after its deployment and thus are stuck there. By examining the code of ProxyFactory::distributeByOwner
provided below, it first checks whether the contest has been registered. Subsequently, checks if the contest has surpassed its expiration period. Only then it calls ProxyFactory::_distribute
.
However there is no validation that the proxy address argument matches the address corresponding to the contest salt. If the caller sends the organizer
, contestId
, implementation
values corresponding to a valid expired contest, but sends the proxy
address of non-expired contest, the saltToCloseTime[salt] == 0
and saltToCloseTime[salt] + EXPIRATION_TIME > block.timestamp
checks will pass and _distribute
will be called on a non-expired contest.
This allows the owner (either maliciously or by mistake) to distribute the rewards of a contest before its expiration time. The code comments make it clear that this is not the intended behaviour ("// distribute only when it exists and expired"). However as the owner role is supposed to be trusted, I classify this as a low vulnerability issue.
The internal logic of the ProxyFactory::distributeByOwner
does not corresponds to its expected behaviour. Owner can call ProxyFactory::distributeByOwner
on a non-expired contest.
Manual Review
Consider computing the proxy address derived from the salt
parameter and check that proxy
matches the computed one. As shown in the diff below.
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.