Signatures may be reused across different contracts
Description
On the Arbitrum side, the bridge operates by allowing users to perform actions approved by validators. For instance, to request a withdrawal, the user needs at least two thirds of the validators (if validator power is equally distributed) to sign off using their in-memory hot keys. The bridge checks these signatures, and if the user is indeed permitted to perform the withdrawal, it transfers them the USDC.
Currently, signatures include a domain separator to prevent reuse across different chains and projects. This is important to ensure that they are specific to the context in which they are used and cannot be maliciously repurposed.
function makeDomainSeparator() view returns (bytes32) {
return
keccak256(
abi.encode(
EIP712_DOMAIN_SEPARATOR,
keccak256(bytes("Exchange")),
keccak256(bytes("1")),
block.chainid,
VERIFYING_CONTRACT
)
);
}
However, the signatures do not include the contract or token address.
Impact
The fact that the domain separator does not by default include any contract-specific data introduces some maintenance risk: the protocol must ensure that signatures cannot be reused across contracts on the same chain.
For instance, if the exact same contract were used for a different ERC-20 token, an attacker may be able to steal funds by replaying withdrawal messages.
Recommendations
We recommend including either the contract address or the token address in signatures (either the domain separator or in the message itself) to increase robustness and avoid future issues.
Remediation
This issue has been acknowledged by Hyperliquid, and a fix was implemented in commit 97225667↗.