Sparkn

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

Signature Replay in Proxy Factory

Summary

The protocol is susceptible to signature replay attacks due to the lack of fields on which the message is signed.

Vulnerability Details

The protocol does not use any signature timestamp (after which the signature is not useable) or a nonce ( a number unique to every user) inside ProxyFactory#deployProxyAndDistributeBySignature.

In fact, it uses the following method that can for sure prevent the cross-chain signature replay but not across one chain.

bytes32 domainSeparatorV4 = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes("ProxyFactory")),
keccak256(bytes("1")),
block.chainid,
address(proxyFactory)
)
);
bytes32 randomId_ = keccak256(abi.encode("Jason", "001"));
bytes memory sendingData = createData();
bytes32 data = keccak256(abi.encode(randomId_, sendingData));

Impact

Invalid signatures might be accepted in deployProxyAndDistributeBySignature and cause invalid proxy contracts to be deployed by the same person even if they intended to deploy only once.

Tools Used

Manual review

Recommendations

There are two possible solutions:

  • Implement nonce based signing

// declare a user->nonce mapping and check the latest nonce on each deployment from the user
mapping(address=>uint) nonces;
.
.
.
function deployProxyAndDistributeBySignature(
address organizer,
bytes32 contestId,
address implementation,
bytes calldata signature,
uint nonce,
bytes calldata data
) public returns (address) {
require(nonce==nonces(msg.sender),"nonces does not match").
..
..
..
}
  • Implement signatures caching so that multiple signatures can't be replayed.

// declare a user->nonce mapping and check the latest nonce on each deployment from the user
mapping(address=>bool) signatures;
.
.
function deployProxyAndDistributeBySignature(
address organizer,
bytes32 contestId,
address implementation,
bytes calldata signature,
uint nonce,
bytes calldata data
) public returns (address) {
..
require(signatures[signature]==false,"nonces does not match");
signatures[signature]=true;
..
..
..
}

Support

FAQs

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