Instantly share code, notes, and snippets.

Embed
What would you like to do?
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's 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 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 transferring: (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 case of token standard, a token transfer should be considered as an event. 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 the result, the only correct way to make a token deposit to a contract is 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 "WARNIGN: 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. STORJ, $217,477 lost. watch on Etherscan

  5. 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.

@gnostication

This comment has been minimized.

gnostication commented Feb 12, 2018

Thank you, once again, for at least trying to get the Ethereum community to wake up.

ETC is the hope, once the hype of ETH dies.

@SL50

This comment has been minimized.

SL50 commented Feb 12, 2018

It is helpful to name token standards that inherit this vulnerability of ERC20. ERC721 and ERC644 are affected AFAIK.

@Dexaran

This comment has been minimized.

Owner

Dexaran commented Feb 13, 2018

This is a good point.
Many of token standards are just the extensions of ERC20, thus they inherit this bug.

This token standards are affected by ERC20 bug

ERC644: ethereum/EIPs#644

ERC677: ethereum/EIPs#677

ERC721: ethereum/EIPs#721

ERC827: ethereum/EIPs#827

ERC875: ethereum/EIPs#875

This token standards are NOT affected by this bug

ERC223: ethereum/EIPs#223

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: ethereum/EIPs#777

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.

@gtabmx

This comment has been minimized.

gtabmx commented Oct 25, 2018

This isn't a bug insofar as sending an email to an unintended or wrong recipient is, or sending the only copy of your English will to a person in Japan who doesn't speak English. Poor user experience: yes. Bug: no.

Consider this user flow:

  1. User chooses username for a new social media site.
  2. Last registration step is to provide an email where your welcome letter will be sent, as well as your temporary password.
  3. After typing in the email address and clicking submit, the email is fired off, but does not give you the ability to re-send to another address.

If you typed the wrong email or an email you don't have access to, its over. This is not a bug. This is a poor and not properly thought out user experience. The architect and UX designer failed, but the software developer did not.

Calling this "ERC20 transfer to a recipient that cannot speak ERC20" issue a bug is erroneous.

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