DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: medium
Valid

Incorrect domain seperator definition in LibTractor.sol

Summary

The _domainSeparatorV4 is incorrectly calculated using BLUEPRINT_TYPE_HASH instead of the EIP712_TYPE_HASH.

Vulnerability Details

_domainSeparatorV4 is wrongly calculated as it uses BLUEPRINT_TYPE_HASH instead of EIP712_TYPE_HASH causing that the hash calculation be incorrect, making signing impossible.

Looking at the _domainSeparatorV4, the name, version, chainId and address should be encoded, using the equivalent EIP712_TYPE_HASH

function _domainSeparatorV4() internal view returns (bytes32) {
return
keccak256(
abi.encode(
BLUEPRINT_TYPE_HASH,
TRACTOR_HASHED_NAME,
TRACTOR_HASHED_VERSION,
C.getChainId(),
address(this)
)
);
}

The EIP712_TYPE_HASH goes like this, a hash of the name, version, chainId and verifyingContract.

bytes32 private constant EIP712_TYPE_HASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);

However, _domainSeparatorV4 uses BLUEPRINT_TYPE_HASH, which is a hash of the publisher, data, operatorData, maxNonce, startTime and endTime.

bytes32 public constant BLUEPRINT_TYPE_HASH =
keccak256(
"Blueprint(address publisher,bytes data,bytes operatorData,uint256 maxNonce,uint256 startTime,uint256 endTime)"
);

This makes the encoded data wrong.

Impact

The _domainSeparatorV4 is used to calculate _hashTypedDataV4,

function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));
}

which is used to calculate blueprint hash.

function _getBlueprintHash(Blueprint calldata blueprint) internal view returns (bytes32) {
return
_hashTypedDataV4(
keccak256(
abi.encode(
BLUEPRINT_TYPE_HASH,
blueprint.publisher,
keccak256(blueprint.data),
keccak256(abi.encodePacked(blueprint.operatorPasteInstrs)),
blueprint.maxNonce,
blueprint.startTime,
blueprint.endTime
)
)
);
}

This is then used the verifyRequisition modifier, which is used when publishing, cancelling and executing tractor blueprints.

modifier verifyRequisition(LibTractor.Requisition calldata requisition) {
bytes32 blueprintHash = LibTractor._getBlueprintHash(requisition.blueprint);
require(blueprintHash == requisition.blueprintHash, "TractorFacet: invalid hash");
address signer = ECDSA.recover(
MessageHashUtils.toEthSignedMessageHash(requisition.blueprintHash),
requisition.signature
);
require(signer == requisition.blueprint.publisher, "TractorFacet: signer mismatch");
_;
}

As established, since the calculated hash is incorrect, requisition verification will always fail when the signers attempt to perform the above mentioned operations in TractorFacet.sol (which are its core functions), rendering the contract practically unusable.

Tools Used

Manual Review

Recommendations

Recommend using the EIP712_TYPE_HASH instead.

function _domainSeparatorV4() internal view returns (bytes32) {
return
keccak256(
abi.encode(
- BLUEPRINT_TYPE_HASH,
+ EIP712_TYPE_HASH,
TRACTOR_HASHED_NAME,
TRACTOR_HASHED_VERSION,
C.getChainId(),
address(this)
)
);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Tractor not compliant to EIP712 requirement because it's using the type hash of the blueprint, not the EIP712Domain

Appeal created

inh3l Submitter
11 months ago
inallhonesty Lead Judge
11 months ago
inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Tractor not compliant to EIP712 requirement because it's using the type hash of the blueprint, not the EIP712Domain

Support

FAQs

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