Mammoth Mocha Koala
Medium
The Verifier contract fails to enforce that a signed message’s domain field (if set) matches the address of the contract calling the verification function (msg.sender). This allows signatures intended for one context (e.g., a specific market) to be replayed in unintended contexts (e.g., a different market), violating domain isolation and enabling signature reuse across domains
function verifyFill(Fill calldata fill, bytes calldata signature)
external
validateAndCancel(fill.common, signature)
{
if (!SignatureChecker.isValidSignatureNow(
fill.common.signer,
_hashTypedDataV4(FillLib.hash(fill)),
signature
)) revert VerifierInvalidSignerError();
}
EIP-712 signatures include a domain separator to cryptographically bind a signature to a specific context (e.g., a specific contract or "domain"). This prevents replaying signatures across different contexts.
In the Verifier contract, messages like Fill, Intent, or Take include a common.domain field. If set, this domain should restrict the message’s validity to only the specified contract (e.g., a market address).
The Verifier contract does not validate that msg.sender matches common.domain during signature verification. For example:
function verifyFill(Fill calldata fill, bytes calldata signature)
external
validateAndCancel(fill.common, signature)
{
// No check that msg.sender == fill.common.domain
if (!SignatureChecker.isValidSignatureNow(...)) revert(...);
}
This allows a malicious actor to submit a message with domain = Market A to Market B, bypassing the intended domain isolation.
No response
No response
Valid Signature for Market A:
A user signs a Fill message with domain = Market A.
The message is intended to execute a trade only in Market A.
Replay Attack on Market B:
An attacker calls Verifier.verifyFill(fillMessage, signature) from Market B (not Market A).
The Verifier approves the signature because it does not check if msg.sender == fill.common.domain.
Unauthorized Execution:
Market B processes the fill intended for Market A, leading to unintended trades, liquidity manipulation, or financial loss.
Attackers can reuse signatures in unintended contexts (e.g., different markets). Valid signatures meant for one domain can execute actions in another domain, violating trust boundaries.
No response
Add a check to enforce that msg.sender matches the common.domain (if the domain is set):
modifier validateDomain(Common calldata common) { if (common.domain != address(0) && common.domain != msg.sender) { revert VerifierInvalidDomainError(); } _; }
// Apply modifier to verification functions: function verifyFill(Fill calldata fill, bytes calldata signature) external validateDomain(fill.common) // validateAndCancel(fill.common, signature) { // ... }