The criteria for creating a contest, as per what's written in the code, is that effectively the combination of organizer, contestId, and implementation for a contest needs to be unique. This is because those values are used to create the salt which is used during the Proxy contract creation. This leads to an edge case where the implementation address is changed in the future, but a contest with the same contestId and organizer is created. When a signature was created by the organizer for the older contest, this signature can also be used for this newer contest.
This is because the digest in the deployProxyAndDistributeBySignature function only includes the data and contestId (and also the organizer implicitly, as they signed it). It doesn't include the implementation address. This means that any implementation address can be used for this signature, as long as the contestId and organizer are the same.
Let's consider the case where the malicious user won most of the rewards in the first contest, but did not participate in the second contest. They can re-use the first signature to send themselves the rewards from the second contest (assuming reward token is the same).
Consider the deployProxyAndDistributeBySignature function which allows any user to take a signature by an organizer and deploy the Proxy & distribute the funds:
Since the implementation address isn't part of the digest, a signature will be accepted for any contest, as long as the organizer, contestId, and data are the same. This can lead to the following exploit:
A first contest is created in which User A will be awarded the most tokens, this uses implementation-1
The organizer for the first contest creates a signature, which another user calls deployProxyAndDistributeBySignature with; User A is awarded most of the rewards
The same organizer decides to create another contest, but this time using implementation-2 (which has slightly different logic, but the API is the same) - this uses the same contestId as the first contest; User B is intended to get the most awards from this second contest
User A uses the same signature from the first contest & receives most of the rewards from the second contest
Signatures can be replayed when a similar contest is created, which can lead to a direct loss of funds.
Manual review
Include the implementation address in the digest in the deployProxyAndDistributeBySignature function. Alternatively, provide a deadline value in the digest.
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.