The signature required for resolving contest in ProxyFactory#deployProxyAndDistributeBySignature()
fails to account for implementation address. The unique contest, and therefore an unique proxy instance, is identified by salt
computed using three parameters: organizer
, contestId
and implementation
. However, the signed message only includes organizer
and contestId
.
This creates an unique attack vector. If a contest is hosted on two different implementations simultaneously - let's say V1 and V2 - then it is considered two separate contests with separate proxies by the protocol, as each of them will be identified by different salts. However, the signature provided by the organizer to resolve the contest on implementation V1 may be reused by the winner to claim the tokens from the contents on implementation V2 as well.
The documentation describes the Proxy
contract in the following way:
This is a proxy contract. It will be deployed by the factory contract. This contract is paired with every single contest in the protocol
Each contest, and each proxy instance, is uniquely identified by the salt, which is calculated as follows:
Three parameters are used to calculate the unique salt - organizer
, contestId
and implementation
.
When the contest closes, the organizer can resolve it providing the list of selected winners, along with the percentage of the pool that each player is eligible for. The organizer can either resolve the contest by himself or provide a meta-transaction. The latter can be used in ProxyFactory#deployProxyAndDistributeBySignature()
method.
The problem lays within the fact that the organizer is required only to sign contestId
and data
, as can be seen in the code snippet below:
If there is another contest with the same organizer and ID, but with different implementation address, it will be considered a separate contest. It will have unique salt and unique proxy address. However, the signature will be valid for that contest as well.
To find out if the scenario like this is possible, let's consult the documentation:
Proxy contracts are supposed to be disposed after the contest is over. If there is a need to upgrade the protocol, we will just create a new implementation contract and deploy proxies with the new implementation contract. And so is the factory contract.
The following scenario is therefore possible:
Alice creates contest, which receives the ID = 1
, let's call it Contest1. She has created that providing the current implementation address, let's call it ImplementationV1
.
Before the contest is over, a new implementation becomes available in the protocol - let's call it ImplementationV2
.
Alice decides that she wants to host her Contest1 on the new implementation as well. Please note that the documentation does not exclude such a scenario, and the code itself (namely the presence of implementation's address in the salt calculation) enables it and suggests it is a valid use case.
The Contest1 hosted on ImplementationV1
comes to an end. Alice decides that Bob will be the solo winner of it, and provides a meta-transaction to resolve the contest via ProxyFactory#deployProxyAndDistributeBySignature()
method.
Later on, the Contest1 hosted on ImplementationV2
comes to an end as well. Please note that this contest has a different Proxy address than the one hosted on ImplementationV1
, therefore it has a separate pool of prizes.
Much more supporters participated in the Contest1 on ImplementationV2
, therefore Alice wants to divide the pool between multiple winners...
...however Bob is able to steal the pool, utilizing a replay attack vector. The signature that Alice has provided for the ImplementationV1
pool is valid for this pool, too. Therefore Bob calls ProxyFactory#deployProxyAndDistributeBySignature()
method, reusing the aforementioned signature, and makes himself the only winner again.
A proof of concept for the attack is provided below. Please paste this code inside the ProxyFactoryTest.t.sol
and run it with the following command: forge test --match-test testAttackerMayReuseSignatureForDifferentImplementation
.
Impact is High, as the tokens may be stolen from the protocol by the malicious supporter.
Likelihood is Medium, as the protocol upgrades are very likely to happen in the near future, as stated by the Protocol's Team in the documentation and during the live stream.
Severity is therefore estimated as High.
Manual Review
Disallow the aforementioned scenario in the user interface and/or include the implementation
address in the message 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.