DittoETH

Ditto
DeFiFoundryOracle
55,000 USDC
View results
Submission Details
Severity: high
Invalid

`permit` function can be `frontrun` by MEV bots or by Attackers.

Summary

Security Considerations Mentioned in IERC20Permit.sol

There are two important considerations concerning the use of permit.

  1. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way.

  2. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be front-run. A protocol that uses permits should take this into consideration and allow a permit call to fail.

Vulnerability Details

contract Ditto is ERC20, ERC20Permit, ERC20Votes {

Ditto.sol - Line 10

The Ditto contract inherits the ERC20Permit contract but does not handle this function inside the contract.

function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
require(signer == owner, "ERC20Permit: invalid signature");
_approve(owner, spender, value);
}

The permit function is public and is vulnerable to front-run attacks as mentioned above in the summary section.

This function takes the spender address, so anyone who uses the permit function to give the allowance to any spender address can be front-run and an attacker can pass his address in the spender parameter and will get the tokens.

* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also applies here.

IERC20Permit.sol - Line 47 - 48

The note is also mentioned in the IERC20Permit contract.

Impact

Anyone who gives allowance to anyone using the permit function can lose his all funds before even the receive claim the allowance.

Tools Used

Manual Review

Recommendations

A recommendation is already mentioned in the IERC20Permit contract;

* Combining these two aspects, a pattern that may be generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.
Updates

Lead Judging Commences

0xnevi Lead Judge
about 2 years ago
0xnevi Lead Judge about 2 years ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.