This repository has been archived by the owner on Jan 12, 2025. It is now read-only.
Matin - ERC20 permit()
calls can be front-ran and user deposit tasks can be DoSed
#37
Labels
Non-Reward
This issue will not receive a payout
Matin
Medium
ERC20
permit()
calls can be front-ran and user deposit tasks can be DoSedSummary
The
permit()
functionality which is used inside the market and user manager contracts, lacks protection against front-running attacks, which can lead to a denial of service (DoS) for user deposits.Vulnerability Detail
The
permit()
function verifies if the provided signature matches the owner or signer of the message but does not check who executes thepermit()
. Thus, Alice can grant a permit to Bob, but John could use it on behalf of Alice or Bob. While not inherently problematic, this becomes an issue in transaction call chains susceptible to front-running. If a permit call is front-ran, the transaction will revert because using an already utilized signature will fail.The issue exists within the market and user manager contracts that enable the
permit()
feature, allowing users to perform important tasks like staking and borrow repayment using permits.In the context of staking with a permit: (Staking among other tasks is selected for illustration)
stakeWithERC20Permit()
, providing the permits, which callspermit()
to execute the permit and complete the staking.However, when Alice grants these permits to Bob and he tries to execute them, the signature details are exposed to the mempool. A malicious user can:
stakeWithERC20Permit()
call, directly call ERC20permit()
, and use the signature.Bob's attempt to stake on Alice's behalf would then fail because the signature he provided is already used, causing a revert when he reaches
permit()
.For more information, refer to this article.
Impact
The
permit()
function does not verify the executor's identity, enabling front-running attacks. Malicious users can exploit this by using exposed permit signatures from the mempool, causing legitimate transactions to revert. This can disrupt processes like staking with permits, leading to denial of service and wasted gas fees for users.Code Snippet
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/user/UserManagerERC20.sol#L19-L30
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/user/UserManagerDAI.sol#L20-L33
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/user/UserManager.sol#L703-L713
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/market/UDai.sol#L9-L24
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/market/UErc20.sol#L8-L22
Proof of Concept
Tool used
Manual Review
Recommendation
Similar to the solution proposed in the linked article, wrap each
permit()
call in atry/catch
block. This will prevent already granted permissions from causing the entire call chain to revert, allowing the transaction to proceed and use the granted allowance as intended.Duplicate of #65
The text was updated successfully, but these errors were encountered: