Ethereum Name Service Audit

Shayan Eskandari
Apr 29 · 3 min read

recently conducted an audit on to the Ethereum Name Service (ENS). The changes, which roll out on May 4th, 2019, include a yearly rent model that replaces the old auction system and a new DNS integration that will open up ENS names under ~1300 top-level domains.

Our is publicly available.

The focus of the audit was to verify that the smart contract system is secure, resilient and working according to its specifications. The audit activities can be grouped in the following three categories:

  • Security: Identifying security related issues within each contract and within the system of contracts.
  • Sound Architecture: Evaluation of the architecture of this system through the lens of established smart contract best practices and general software best practices.
  • Code Correctness and Quality: A full review of the contract source code.

Audit Details

Audit Details — Issues found: 3 Critical, 1 Major, 5 Medium and 6 Minor.

The audit team found some interesting bugs during this audit. We expand on two of the findings here.


Front-running is a pervasive issue on blockchain. It is really challenging to foresee all possible race conditions in the logic of the DApp. We previously published extensively on the fact that front-running is a very common type of security vulnerability in Ethereum DApps.

ENS has been one of the cutting edge DApps in the Ethereum ecosystem, starting back in April 2016 as . ENS famously implemented for initial registration of the domains through , and used to prevent domain sniping and front-running.

As mentioned before, making DApps resilient against front-running is hard. Even though the ETHRegistrarController smart contract uses a proper commit and reveal scheme to prevent front-running, failing to include even one crucial variable can lead to opening up the attack vector again. On the implementation under audit, the owner was not included in the committed message, making it vulnerable to front-running, which allowed the commitment transaction to be revealed and registered by any address.

The solution? include the right set of data the user is committing. You can read more about this specific issue and the remediation here:

Memory Corruption

This was an interesting find. On the last few days of the audit, when we thought we have gone through every piece of code in the scope, we decided to expand our search and look at the libraries used in the main contracts. buffer.sol was out of the scope but it was used throughout the main contracts.

buffer.init function was implemented as following:

function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
if (capacity % 32 != 0) {
capacity += 32 - (capacity % 32);
// Allocate space for the buffer data
buf.capacity = capacity;
assembly {
let ptr := mload(0x40)
mstore(buf, ptr)
mstore(ptr, 0)
mstore(0x40, add(ptr, capacity))
return buf;

Note that memory is reserved only for capacity bytes, but the bytes actually requires capacity + 32 bytes to account for the prefixed array length. Other functions in Buffer assume correct allocation and therefore corrupt nearby memory.

You can read more about this issue and the remediation here:

If you are interested in knowing more about the services ConsenSys Diligence offers, � �.

ConsenSys Diligence

ConsenSys Diligence has the mission of solving Ethereum smart contract security. Contact us for an audit at

Thanks to Gonçalo Sá, Steve Marx, and Maurelian.

Shayan Eskandari

Written by

Blockchain/Security Engineer, PhD Candidate

ConsenSys Diligence

ConsenSys Diligence has the mission of solving Ethereum smart contract security. Contact us for an audit at