Is DeFi a moth again? Ethereum smart wallet application Authenticeum exposed to fatal vulnerability

Recently, the Ethereum smart wallet application Authenticeum, which has been invested by institutions such as Coinbase Ventures, received a vulnerability disclosure from samczsun, which exploited the sequence of operations of the account contract meta-transaction function and allowed the attacker to control the wallet account. After receiving the feedback, the Authenticeum team quickly resolved the vulnerability to avoid loss of user funds. It is reported that in order to solve this problem, Authenticeum used the vulnerability to force the user account to be upgraded to a repair implementation, and then returned control to the user.

The following is the disclosure details of this vulnerability. The author is a professional white hat samczsun and has disclosed serious vulnerabilities in projects such as 0x.

Long story short:

The Authereum wallet contains a vulnerability that an attacker could use to take over any wallet at any time. The Authereum team used this vulnerability to force an upgrade of all user wallets, so no funds were lost.

About Authenticeum

Authereum is a project designed to make it easier for users to use the Ethereum dApp. To achieve this, they have established a set of smart contracts to act as a smart wallet.

Each smart wallet is owned by a set of admin keys, and the first admin key is generated when a user creates an account on Authenticeum. Naturally, management keys can add new management keys.

The Authereum wallet also allows relayers to submit transactions, so end users don't have to worry about paying gas fees. To ensure that the relayer cannot cause damage by doing bad things, the Authenticeum wallet verifies that the relayed transaction has been signed by the management key.

How to relay a transaction

Let's look at how relayers use Authoreum meta transactions to relay an ERC20 approved transaction.

First, users provide coded transactions. This includes the target contract, the amount of ETH to be sent, the gas limit, and transaction data. For an ERC20 approved transaction, it might look like this:


Next, the user specifies the minimum gas price they want to send this transaction, and the estimated gas cost. Users also specify whether they want to pay with tokens other than ETH, and the rate at which ETH is converted into related tokens.

Finally, the user provides an administrative key signature. Specifically, it is the signature of the following data.



After providing the executeMultipleAuthKeyMetaTransactions with all the necessary information, they will submit a transaction to the function executeMultipleAuthKeyMetaTransactions , which looks like this:



At this point, the Authenticeum wallet will automatically execute all transactions, verify that the transaction has been signed with a management key, and then refund it if necessary.

Notice the problem?

Problems with meta transactions

If managers can use meta-transactions to relay certain transactions, then it would be nice if they could use meta-transactions to relay all transactions. However, the only reliable way to ensure that a manager sends a transaction is to check msg.sender , which does not work in a meta-transaction.

In fact, if we think about it, wallets represent managers. Only managers can authorize transactions to be sent. This means that if the wallet is a caller, the manager must have authorized the wallet to make self-invocations, right? So maybe we can think of the wallet as some kind of fake manager and let it perform some terrible privileges.



I hope no one will use this version of the wallet to call a random function, because it will be really bad.



Oops Oops Oops:


Oops oops oops oops oops:


The full attack method can be found here:



Fortunately, Authenticeum has just launched, and there is actually no money to steal.


The Authereum team repositioned the signature check before executing the transaction.

 function executeMultipleAuthKeyMetaTransactions( bytes[] memory _transactions, uint256 _gasPrice, uint256 _gasOverhead, address _feeTokenAddress, uint256 _feeTokenRate, bytes memory _transactionMessageHashSignature ) public returns (bytes[] memory) { uint256 _startGas = gasleft(); 

// Hash the parameters bytes32 _transactionMessageHash = keccak256 (abi.encode (address (this), msg.sig, getChainId (), nonce, _transactions, _gasPrice, _gasOverhead, _feeTokenAddress, _feeTokenRate)). ToEthSignedMessageHash ();

// Validate the signer // NOTE: This must be done prior to the _atomicExecuteMultipleMetaTransactions () call for security purposes _validateAuthKeyMetaTransactionSigs (_transactionMessageHash, _transactionMessageHashSignature);

(, bytes [] memory _returnValues) = _atomicExecuteMultipleMetaTransactions (_transactions, _gasPrice, _gasOverhead, _feeTokenAddress, _feeTokenRate);

if (_shouldRefund (_transactions)) {_issueRefund (_startGas, _gasPrice, _gasOverhead, _feeTokenAddress, _feeTokenRate);}

return _returnValues;}

Further reading:

  1. How the Parity wallet was stolen ;
  2. Disclosure by the Authereum team ;