The bug report described an inflation vulnerability that, if exploited, would allow to mint an infinite supply of ETH in the Aurora Engine. That artificial ETH could then have been used to drain of all ETH in the bridge contract on Ethereum (more than 70k ETH at the time of the report, about $204M). Furthermore, the artificial ETH would also allow to drain all tokens from the liquidity pools containing ETH on Aurora and NEAR, also putting these tokens at risk.
Swiftly after the bug has been confirmed a patch was developed and deployed on both mainnet and testnet.
As a reward for the responsible disclosure, the white hat hacker pwning.eth has been awarded $6M in AURORA tokens, the maximum possible bounty in our bug bounty program and to our best knowledge, the second-highest bug bounty ever paid in history.
No user funds have been lost.
Details about the vulnerability
When someone does a
DelegateCall to Aurora's ExitToNEAR or ExitToEthereum precompiles they have the ability to not actually send the balance of the EOA resulting in the engine scheduling a withdrawal for them to their NEAR or Ethereum account.
An example would be if an adversary had 1 ETH, they would be able to
DelegateCall exit to NEAR precompile and get 1 ETH back on NEAR's NEP-141 token while retaining the 1 ETH on Aurora. Depositing this 1 ETH back and repeating this process with the 2x balance the adversary had prior, they would be able to exponentially drain the entirety of the locked NEP-141 ETH tokens.
The root cause of the problem
In the exit to NEAR and exit to Ethereum precompiles, the contract address was hardcoded with disregard to how DelegateCall works. When someone calls the contract it comes from the address of the contract always, and not from the input. Also, since the balance is from the EOA and not the contract, there is no transfer of ETH. This results in the Aurora Engine scheduling a transfer from its NEP-141 ETH balance to the adversary while it has not received an ETH transfer.
Confirmation of the problem
A live test on the testnet was performed by Aurora Labs to confirm the bug, using the exact Solidity contract provided by the author of the exploit.
Instead of removing the hardcoded contract address, given context, it turned out to be better to instead return an exit error if the address given does not match the inputs' address. This yields the same desired result. It effectively disables the ability to call the contract with DelegateCall, much like how it's already done with StaticCall. An accompanying test was produced to ensure that the vulnerability will be tracked in case a logic change causes it to resurface.
The bug bounty program with Immunefi proved to be very valuable in incentivizing white hat hackers to look at the Aurora code base and responsibly disclose bugs.
Aurora Labs looks at its bug bounty program as the last step in a layered defense approach and will use this bug as a learning opportunity to improve earlier steps, like internal code reviews and external audits.
Such a vulnerability should have been discovered at an earlier stage of the defense pipeline and Aurora Labs has already started improving its methods to achieve that in the nearest future.
However, this event ultimately proves that the ecosystem created around Aurora Labs' security mechanisms actually works.