Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow Address Poisoning in ERC20 #353

Open
alex-ppg opened this issue Jan 5, 2023 · 3 comments
Open

Disallow Address Poisoning in ERC20 #353

alex-ppg opened this issue Jan 5, 2023 · 3 comments

Comments

@alex-ppg
Copy link

alex-ppg commented Jan 5, 2023

This is a duplicate of an issue I opened in the OpenZeppelin repository with regard to the address poisoning attack we have seen being repetitively exploited in the wild. As they are going to introduce a change for this particular issue, we believe it should be replicated in the solmate dependency as well given its popularity.

📝 Details

The current token contract implementation of the EIP-20 standard does not satisfy all SHOULD clauses of the standard definition and as such permits the commonly-known address poisoning attack by executing transferFrom instructions from arbitrary addresses with an amount of 0.

The problem arises from how transferFrom evaluates the approval between the caller and the sender of the funds. In the EIP-20 standard, the following statement is present:

The function SHOULD throw unless the _from account has deliberately authorized the sender of the message via some mechanism

This condition is not validated for zero-value transfers as no "deliberate" approval is evaluated. To ensure we remain compliant with the EIP-20 standard in full, we cannot disallow zero-value transfers altogether.

As a workaround, we propose that the if clause within transferFrom is refactored to enforce a non-zero approval between the sender of funds and the msg.sender via a require check or if-revert pattern, either of which is acceptable.

This change will ensure maximal compatibility with existing contract systems, conform to the EIP-20 standard to a greater degree, and address the address poisoning attack we have seen being extensively exploited in recent times.

🔢 Code to reproduce bug

A simple Solidity smart contract to illustrate the bug in action:

import "@solmate/tokens/ERC20.sol";

contract Poisoning {
    ERC20 public immutable token;

    constructor() {
        token = new ERC20("Test", "TST", 18);
    }

    function poison(address from_, address to_) external {
        require(token.allowance(from_, address(this)) == 0);
        token.transferFrom(from_, to_, 0);
    }
}

Invoking the poison function with arbitrary from_ and to_ arguments will successfully perform a transferFrom invocation even when the approval between from_ (the sender of funds) and address(this) (the caller of the transferFrom function) has been set to 0.

This behaviour permits polluting the transfer history of an account on blockchain explorers which in turn can cause users to be misled and copy incorrect addresses when performing their own valid transfers.

@transmissions11
Copy link
Owner

i consider this to be pretty low severity as its entirely PEBCAK, likely a wontfix from me but will leave open in case others have a strong opinion

@alex-ppg
Copy link
Author

alex-ppg commented Jan 6, 2023

While the victimization is a PEBCAK issue (many are surprised it even works including me), block explorers as well as personal wallets being polluted with transactions that overpopulate transaction history is a nuisance. Additionally, the EIP-20 standard itself contains a SHOULD clause which is not being enforced and logically should be. Just some additional points to consider.

@alex-ppg
Copy link
Author

alex-ppg commented Jan 8, 2023

Based on on-chain code analysis of existing DeFi projects, this change should never be applied as it can break existing patterns. For more information, consult: OpenZeppelin/openzeppelin-contracts#3931 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants