Signature replay allows unauthorized migrations
Description
The migrate
function in the contract enables users to convert their tokens into lvlUSD. For a migration to proceed, it must first be authorized by the levelSigner
contract. To verify the migration, the contract generates a hash that includes the migrator's address, the signature's expiration date, the contract's address, and the current chain ID.
function migrate(
address[] calldata _tokens,
address _migratorContract,
address _destination,
uint256 _signatureExpiry,
bytes calldata _authorizationSignatureFromLevel
) external {
uint256[] memory _amounts = _migrateChecks(
msg.sender,
_tokens,
_signatureExpiry,
_migratorContract
);
bytes32 constructedHash = keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
keccak256(
abi.encodePacked(
_migratorContract,
_signatureExpiry,
address(this),
block.chainid
)
)
)
);
//...
Then the signature provided as an argument is verified to be correct with respect to the levelSigner
contract:
// verify that the migrator’s address is signed in the authorization signature by the correct signer (levelSigner)
if (
!SignatureChecker.isValidSignatureNow(
levelSigner,
constructedHash,
_authorizationSignatureFromLevel
)
) {
revert SignatureInvalid();
}
However, there is no mechanism in place to prevent the same signature from being replayed to authorize other user migrations.
Impact
If another user obtains a valid signature from the levelSigner
contract, they can replay the signature before the _signatureExpiry
time, allowing them to migrate their tokens without proper authorization.
Recommendations
We recommend that this function include nonces to prevent replay attacks and add the sender's address to the hash, binding the signature to a specific user.
Remediation
Level disabled the migrate functionality and asked users to withdraw funds and convert them to lvlUSD tokens by other means. The signer address was set to 0x000000000000000000000000000000000000dEaD
to prevent reusing previous signatures or creating new ones. Only the owner of the contract can change the signer address and the owner address is managed by a multisignature administration. In addition, critical alerts have been added to Level's monitor system detecting new transactions changing the signer address.