Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nimbosa/868f092d8aa40643ba415edf39e60c49 to your computer and use it in GitHub Desktop.
Save nimbosa/868f092d8aa40643ba415edf39e60c49 to your computer and use it in GitHub Desktop.
ERC20 token standard vulnerability classification.

Previously described at: ERC20 critical problems medium article.

Description.

ERC20 is the most common Ethereum token standard. It should be noted that it is also the first Ethereum token standard as well.

It is also important that the original ERC20 proposal is a definition of token interface. EIP20 does not define a reference implementation for this token standard. Here is the OpenZeppelin implementation of ERC20 token: https://github.com/OpenZeppelin/zeppelin-solidity/tree/master/contracts/token/ERC20

ERC20 token standard implementation assumes two ways of token transfer: 1.) transfer function; and 2.) approve + transferFrom pattern.

It should be noted that event handling is a well-known and standard practice in programming. In the case of token standards, a token transfer should be considered as an event. The transfer function of ERC20 does not provide any opportunity to handle the transfer, i.e. it is silently increasing balance of the receiver. It is impossible for the receiver to recognize that transfer occurs if the receiver is a contract. As a result, the only correct way to make a token deposit to a contract is through the approve + transferFrom pattern.

It is obvious that in case of a mistake, the transfer function MUST throw an error and revert a wrong transaction. Otherwise it will cause negative consequences (lost tokens) for end user. This is a very common and default practice in programming, called Exception Handling: https://en.wikipedia.org/wiki/Exception_handling

This has already led to the loss of millions of dollars for the whole Ethereum ecosystem at the moment. For more information on money loss read Lost Tokens section.

How it is causing money losses.

Expected transaction behavior: a transaction is executed and it is resulting in value transfer. In case of error, transfer of value will not occur.

This works exactly as expected in case of Ether transfers. If you send Ether to a contract that is not intended to work with Ether then the transaction will be rejected by the recipient smart-contract and the transfer of value will not occur.

This does not work as expected in case of ERC20 token. The transfer of tokens (i.e. transfer of value) will not be reverted or rejected by the recipient smart-contract due to lack of possibility to handle the transfer function invocations. This is causing unexpected transfer function behavior and produce unexpected result i.e. loss of funds for end users.

I often heard how developers declare: (1) "Not a bug, user mistake"; or (2) "This is not a bug or a security vulnerability, this is a specific feature of ERC20 standard design".

I'll explain why the described property of ERC20 standard is exactly a bug below.

REMINDER: Also, if a "specific feature of software design" has caused losses of millions of dollars for software users, then it is an awful design at least.

ERC20 token standard bug explanation.

Software bug definition: https://en.wikipedia.org/wiki/Software_bug

I will quote this:

A software bug is an error, flaw, failure or fault in a computer program or system that causes it to produce an incorrect or unexpected result, or to behave in unintended ways.

The intention of transfer function is to transfer tokens.

This is how the transfer function is specified at the ERC20 token standard:

transfer
function transfer(address _to, uint256 _value) returns (bool success)

Send _value amount of tokens to address _to

There is no phrase like "If you send your tokens to the address or a contract that is not intended to work with tokens then your tokens are permanently lost." We should keep in mind that we are talking about the Ethereum smart-contracts. In case of Ether transaction, every time a transaction is invoked incorrectly (a receiver is unable to handle transaction or a receiver is a contract that is not intended to work with Ether), an error is thrown and the transaction is reverted.

Thus, the expected behavior is that in the event of an error caused by the recipient's inability to handle the incoming transaction, such a transaction should fail.

Ethereum users are often familiar with Ether transactions. As the result, the expected behavior is that if a transfer of tokens is invoked incorrectly (a receiver is unable to handle transaction or a receiver is a contract that is not intended to work with Ether tokens), an error must be thrown.

The statement "... produce an incorrect or unexpected result, or to behave in unintended ways", which is a property of a program error, is of decisive importance here. The "bug of ERC20 transfers" is the unexpected behavior of transfer function in this case.

Some developers could argue that these are my personal assumptions but let's dive deeper into Software Vulnerabilities definition first: https://en.wikipedia.org/wiki/Vulnerability_(computing)#Software_vulnerabilities

I will quote this:

Common types of software flaws that lead to vulnerabilities include: ... Blaming the Victim prompting a user to make a security decision without giving the user enough information to answer it.

The statement "... prompting a user to make a security decision without giving the user enough information to answer it. " which is a property of Software Vulnerability, is of decisive importance here.

There is no sufficient information at the ERC20 token standard definition about the behavior of transfer function in case of the error-handling. A phrase "WARNING: If you will call this function to transfer your tokens to any contract then your tokens are permanently lost." MUST be added to the definition of transfer function of the ERC20 token standard.

A phrase "Calling the transfer function to transfer your tokens to contracts is prohibited in this token standard." MUST be added to the Abstract section of the ERC #20 token standard.

This is required to make each token and UI developer aware of what they are working with. This is what is missing at ERC20 standard.

As soon as this will be implemented, each token developer and UI developer MUST place a big red banner "WARNING: You are attempting to use ERC20 token, you should know that if you call a transfer function to send tokens to a contract then your tokens are permanently lost." Otherwise it will be a Software Vulnerability: User Interface fault (https://en.wikipedia.org/wiki/User_interface).

Lost tokens computed at 27 Dec, 2017.

  1. QTUM, $1,204,273 lost. watch on Etherscan

  2. EOS, $1,015,131 lost. watch on Etherscan

  3. GNT, $249,627 lost. watch on Etherscan

  4. ZRX (0x), $217,477 lost. watch on Etherscan

  5. TRX (Tronix), $201,232 lost. watch on Etherscan

  6. DGD, $151,826 lost. watch on Etherscan

  7. OMG, $149,941 lost. watch on Etherscan

  8. STORJ, $102,560 lost. watch on Etherscan

These are only 8 token contracts that are shown as an example. Each Ethereum contract is a potential token trap for all the ERC20 tokens, thus, there are much more losses than I showed here.

Such contracts that are designed to work with tokens are at very danger zone: state channels, decentralized exchanges, payment services that accept tokens.

Conclusion.

Let me summarize what is stated above. The specific feature of ERC20 token standard design that caused millions of dollars loss for token users IS a Software Bug and it can be classified as Software Vulnerability.

The specific design of ERC20 token standard functionality is producing unexpected result and causing unexpected behavior which is a property of software bug.

As ERC20 token standard is a smart-contract interface specification, then I can say that Interface fault, such as Blaming The Victim is taking place here. This is also a property of software vulnerability.

Saying "This is not a bug" is absolutely wrong. Definitely, this is a bug and a vulnerability. Saying "This is a user mistake" is a kind of Blaming the victim.

Postscript.

Many token standards are just extensions of ERC20, thus they inherit this bug.

These token standards are affected by ERC20 bug:

  1. ERC644: ethereum/EIPs#644

  2. ERC677: ethereum/EIPs#677

  3. ERC721: ethereum/EIPs#721

  4. ERC827: ethereum/EIPs#827

  5. ERC875: ethereum/EIPs#875

These token standards are NOT affected by this bug

ERC223 token standard is specially designed to resolve this problem. As the result, it overrides the transfer function and explicitly defines its behavior. ERC223 token can not be affected by this bug.

ERC777 token standard uses completely different function signatures. It depends on implementation whether a token of ERC777 standard will implement this bug or not. ERC777 standard does not inherit it by default but it does not implement any mechanism to prevent it, thus it is not guaranteed that ERC777 tokens are secure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment