Sparkn

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

Invalid EIP-712 signature schema

Summary

The implementation of EIP-712 used to deploy distributions using meta transactions fails to follow the standard, potentially breaking compatibility.

Vulnerability Details

Organizers can relay the execution of a contest distribution via the deployProxyAndDistributeBySignature() function. This implementation allows an organizer to sign the distribution payload so that anyone can call this function and authorize execution using the signature.

While the intention is clearly to support EIP-712, there are some details that cause the implementation to fail to adhere to the standard, breaking compatibility.

The implementation relies on the OpenZeppelin utility contract for EIP712 and builds the hash using _hashTypedDataV4() in line 159:

140: /**
141: * @notice deploy proxy contract and distribute prize on behalf of organizer
142: * @dev the caller can only control his own contest
143: * @dev It uess EIP712 to verify the signature to avoid replay attacks
144: * @dev front run is allowed because it will only help the tx sender
145: * @param organizer The organizer of the contest
146: * @param contestId The contest id
147: * @param implementation The implementation address
148: * @param signature The signature from organizer
149: * @param data The prize distribution data
150: * @return proxy The proxy address
151: */
152: function deployProxyAndDistributeBySignature(
153: address organizer,
154: bytes32 contestId,
155: address implementation,
156: bytes calldata signature,
157: bytes calldata data
158: ) public returns (address) {
159: bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(contestId, data)));
160: if (ECDSA.recover(digest, signature) != organizer) revert ProxyFactory__InvalidSignature();
...

The _hashTypedDataV4() function expects to receive the hash of the structured data (structHash) and then concatenates it with the domain separator, in accordance with the standard. However, the implementation here is simply building the struct hash by hashing contestId and data (i.e. keccak256(abi.encode(contestId, data))), which contains at least two errors that break the standard.

First, EIP-712 defines a typeHash, which is missing in the implementation. This type hash is a hash of a string representation of the structure of the data. Second, the data attribute is being encoded at it is, while EIP-712 requires it to be encoded as the keccak hash of its contents (see "Definition of encodeData"). For more details about the correct usage, see "Recommendations" section below.

Impact

Medium. EIP-712 structured data hashing standard is not properly implemented.

Tools Used

None.

Recommendations

To properly implement EIP-712 signatures, a structure of the payload needs to be defined. For example, since this represents a distribution that involves a contest id and a data attribute, this could be represented as "Distribution(bytes32 contestId,bytes data)". The type hash is the keccak hash of this string representation. While encoding the payload, the data attribute needs to be first hashed using keccak256.

bytes32 constant public DISTRIBUTION_TYPEHASH = keccak256("Distribution(bytes32 contestId,bytes data)");
function _hashDistribution(bytes32 contestId, bytes memory data) internal pure returns (bytes32) {
return keccak256(
abi.encode(
DISTRIBUTION_TYPEHASH,
contestId,
keccak256(data)
)
);
}
function deployProxyAndDistributeBySignature(
address organizer,
bytes32 contestId,
address implementation,
bytes calldata signature,
bytes calldata data
) public returns (address) {
bytes32 digest = _hashTypedDataV4(_hashDistribution(contestId, data));
...

Support

FAQs

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