Transparent Dishonesty: Taxonomy of front-running attacks on Blockchain
This blog post is based on a paper published at 3rd Workshop on Trusted Smart Contracts In Association with Financial Cryptography (FC) in February 2019. We suggest reading the full version of the paper for complete use cases and detailed description of the attacks and mitigation methods: SoK: Transparent Dishonesty: front-running attacks on Blockchain.
Front-running has been an issue in financial instrument markets since the 1970s. With the advent of blockchain technology, front-running has resurfaced in new forms we explore in our paper, instigated by the blockchain’s decentralized and transparent nature.
Blockchain technology enables decentralized applications (DApps) or smart contracts. Function calls (or transactions) to the DApp are processed by a decentralized network. Transactions are finalized in stages: they (generally) first relay around the network, then are selected by a miner and put into a valid block, and finally, the block is well-enough incorporated in the blockchain that is unlikely to be changed. Front-running is an attack where a malicious node observes a transaction after it is broadcast but before it is finalized, and attempts to have its own transaction confirmed before or instead of the observed transaction.
The mechanics of front-running work on all DApps, but front-running is not necessarily beneficial, depending on the DApp’s internal logic and/or any mitigations it might implement. Therefore, DApps need to be studied individually or in categories. In our paper, we draw from a scattered body of knowledge regarding front-running attacks on blockchain applications and the proposed solutions, with a series of case studies of DApps deployed on Ethereum and also study initial coin offerings (ICOs).
A Taxonomy of Front-running Attacks
As we will illustrate with examples throughout our paper, front-running attacks can often be reduced to one of a few basic templates. We emphasize what the adversary is trying to accomplish (without worrying about how) and we distinguish three cases: displacement, insertion, and suppression attacks. In all three cases, Alice is trying to invoke a function on a contract that is in a particular state, and Mallory will try to invoke her own function call on the same contract in the same state before Alice.
In the first type of attack, a displacement attack, it is not important to the adversary for Alice’s function call to run after Mallory runs her function. Alice’s can be orphaned or run with no meaningful effect. Examples of displacement include: Alice trying to register a domain name and Mallory registering it first; Alice trying to submit a bug to receive a bounty and Mallory stealing it and submitting it first; and Alice trying to submit a bid in an auction and Mallory copying it.
In an insertion attack, after Mallory runs her function, the state of the contract is changed and she needs Alice’s original function to run on this modified state. For example, if Alice places a purchase order on a blockchain asset at a higher price than the best offer, Mallory will insert two transactions: she will purchase at the best offer price and then offer the same asset for sale at Alice’s slightly higher purchase price. If Alice’s transaction is then run after, Mallory will profit on the price difference without having to hold the asset.
In a suppression attack, after Mallory runs her function, she tries to delay Alice from running her function. After the delay, she is indifferent to whether Alice’s function runs or not. We only observe this attack pattern in one DApp and the details are quite specific to it. See Section 4.3 of the paper for more detail.
Each of these attacks have two variants, asymmetric and bulk. In some cases, Alice and Mallory are performing different operations. For example, Alice is trying to cancel an offer, and Mallory is trying to fulfill it first. We call this asymmetric displacement. In other cases, Mallory is trying to run a large set of functions: for example Alice and others are trying to buy a limited set of shares offered by a firm on a blockchain. We call this bulk displacement.
We classify the mitigations into three main categories. In the first category, the blockchain removes the miner’s ability to arbitrarily order transactions and tries to enforce some ordering, or queue, for the transactions. In the second category, cryptographic techniques are used to limit the visibility of transactions, giving the potential front-running less information to base their strategy on. In the final category, DApps are designed from the bottom-up to remove the importance of transaction ordering or time in their operations. We also note that for DApps that are legally well-formed (e.g., with identified parties and a clear jurisdiction), front-running attacks can violate laws, which is its own deterrent.
First-in-first-out (FIFO) is generally not possible on a distributed network because transactions can reach different nodes in a different order.
The vanilla Go-Ethereum (geth) implementation prioritizes transactions based on their gas price and nonce. Because no rule is enforced, miners can sequence transactions in advantageous ways. Nonetheless, some exchanges do centralize time-sensitive functionalities (e.g., EtherDelta and 0xProject) in off-chain order books.
One alternative is to sequence transactions pseudorandomly. This can be seen in proposals like Canonical Transaction Ordering Rule (CTOR) by Bitcoin Cash ABC which adds transactions in lexicographical order according to their hash. Note that Bitcoin does not have a front-running problem for standard transactions. While this could be used by Ethereum to make front-running statistically difficult, the protection is marginal at best and might even exacerbate attacks.
A DApp interaction includes the following components:
the code of the DApp
the current state of the DApp
the name of the function being invoked
the parameters supplied to the function
the invoked contract’s address
the identity of the sender.
Confidentiality applied to a DApp could mean different levels of protection for each of these. For front-running, function calls (3,4) are the most important, however, function calls could be inferred from state changes (2). Hawk and Ekiden are examples of (2,3,4)-confidentiality (with limitations we are glossing over).
The applicability of privacy-preserving blockchains needs to be evaluated on a case-by-case basis. For example, one method used by traditional financial ex- changes in dealing with front-running from high frequency traders is a dark pool: essentially a (2,3,4)-confidential order book maintained by a trusted party. A DApp could disintermediate this trusted party. Users whose balances are affected by changes in the contract’s state would need to be able to learn this information (e.g. Aztec Protocol exchange).
Commit/Reveal. While confidentiality appears insufficient for solving domain name front-running alone, a hybrid approach of sequencing and confidentiality can be effective and is, in fact, an example of an older cryptographic trick known as commit/reveal. The essence of the approach is to protect the function call (e.g., (3,4)- or (4)-confidentiality) until the function is enqueued in a sequence of functions to be executed. Once the sequence is established, the confidentiality is lifted and the function can only be executed in the order it was enqueued (or, generally speaking, not at all).
Recall that a commitment scheme enables one to commit to a digital value while keeping it a secret (hiding), and then open it (and only it: binding) at a later time of the committer’s choosing. A common approach (conjectured to be hiding) is to submit the cryptographic hash of the value with a random nonce (for low entropy data) to a smart contract, and later reveal the original value and nonce which can be verified by the contract to correctly hash to the commitment, as used in Namecoin and Ethereum Naming Service auctions.
Enhanced Commit/Reveal. Submarine Commitments extend the confidentiality of the commit and reveal, so that the commitment transaction is identical to a transaction to a newly generated Ethereum address. They initially hide the contract address being invoked, providing (3,4,5)-confidentiality during the commit phase; and they ensure that if a revealed transaction sent funds, the funds were fully collateralized at commit time.
The final main category of mitigation is to assume front-running is unpreventable and to thus responsively redesign the functionality of the DApp to remove any benefit from it. For example, when designing a decentralized exchange, one can use a call market design instead of a time-sensitive order book to sidestep and disincentivize front-running. In a call market design, the arrival time of orders does not matter as they are executed in batches.
Another example in the design of ERC20 standard is the allowance functionality.
approve() function in the specification allows a second entity to be able to spend N tokens from the sender’s balance. In order to change the allowance, sender must send a transaction to set the new allowance value. Using the insertion attack, attacker could front-run the new allowance transaction and spend the old value before the new value is set, and then additionally spend the new amount at a later time. Solutions such as
decreaseApproval()`/increaseApproval()` were added in updated implementations.
Front-running is a pervasive issue in Ethereum DApps. DApp developers don’t necessarily have the mindset to design DApps with front-running in mind. This is an attempt to bring forward the subject and increase awareness of these type of attacks. While some DApp-level application logic could be built to mitigate these attacks, its ubiquity across different DApp categories suggests mitigations at the blockchain-level would perhaps be more effective. We highlight this as an important research area.
Thinking about smart contract security? We can provide training, ongoing advice, and smart contract auditing. Contact us.