Assessment reports>Points Farm>Critical findings>Signature replay allows unauthorized migrations
Category: Coding Mistakes

Signature replay allows unauthorized migrations

Critical Severity
Critical Impact
Medium Likelihood

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.

Zellic © 2025Back to top ↑