Sparkn

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

Wrong EIP-712 Implementation. `typehash`, `nonce`, `deadline` are missing

Summary

EIP-712 digest should comprise of following.

  • Encoded type

keccak256("Distribute(uint256 contestId,byte32 data,uint256 nonce,uint256 deadline)");
  • Encoded data

(contestId, data, nonce[organizer], deadline);

Vulnerability Details

function deployProxyAndDistributeBySignature(
address organizer,
bytes32 contestId,
address implementation,
bytes calldata signature,
bytes calldata data
) public returns (address) {
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(contestId, data)));
if (ECDSA.recover(digest, signature) != organizer) revert ProxyFactory__InvalidSignature();
bytes32 salt = _calculateSalt(organizer, contestId, implementation);
if (saltToCloseTime[salt] == 0) revert ProxyFactory__ContestIsNotRegistered();
if (saltToCloseTime[salt] > block.timestamp) revert ProxyFactory__ContestIsNotClosed();
address proxy = _deployProxy(organizer, contestId, implementation);
_distribute(proxy, data);
return proxy;
}

Impact

Signature replay attack possible.

Tools Used

Manual Review

Recommendations

+ byte32 DISTRIBUTE_TYPEHASH = keccak256("Distribute(uint256 contest,byte32 data,uint256 nonce)");
+ mapping (bytes32 => uint256) nonce;
function deployProxyAndDistributeBySignature(
address organizer,
bytes32 contestId,
address implementation,
bytes calldata signature,
bytes calldata data,
+ uint256 deadline
) public returns (address) {
- bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(contestId, data)));
+ bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(DISTRIBUTE_TYPEHASH, contestId, data, nonce[contestId]++, deadline)));
+ if (block.timestamp >= deadline) revert ProxyFactory__OldSignature();
if (ECDSA.recover(digest, signature) != organizer) revert ProxyFactory__InvalidSignature();
bytes32 salt = _calculateSalt(organizer, contestId, implementation);
if (saltToCloseTime[salt] == 0) revert ProxyFactory__ContestIsNotRegistered();
if (saltToCloseTime[salt] > block.timestamp) revert ProxyFactory__ContestIsNotClosed();
address proxy = _deployProxy(organizer, contestId, implementation);
_distribute(proxy, data);
return proxy;
}

Support

FAQs

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