-
Notifications
You must be signed in to change notification settings - Fork 4
MohammedRizwan - Permit functions in Union
contracts can be affected by DOS
#65
Comments
Union
contracts can be affected by DOSUnion
contracts can be affected by DOS
In a similar scenario this would usually be exlcuded due to "There are no intended integrations/use cases of removing liquidity with permit that makes it time sensitive (uniswapv2 has been using this same functionality for ages). The user can just call the regular remove liquidity function and they'll be good. It's difficult to consider this more than a low." (sherlock-audit/2024-02-jala-swap-judging#177 (comment)) |
Escalate erc20Token.permit(msg.sender, address(this), amount, deadline, v, r, s); Since they are not the signer of the permit signature: function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
if (block.timestamp > deadline) {
revert ERC2612ExpiredSignature(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);
if (signer != owner) {
revert ERC2612InvalidSigner(signer, owner);
}
_approve(owner, spender, value);
}``` |
You've created a valid escalation! To remove the escalation from consideration: Delete your comment. You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final. |
Uniswap V2 has been using the same functions and approach for years: function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
} I think it should be Low at the very maximum. But the sponsor can make the final decision of course. |
Just for reference, one of the UniV2 functions: |
Even if this was a DOS it would be at most a low as, according to the Sherlock docs, for a DOS to be a medium it must either affect the availability of a time-sensitive function or cause a locking of funds for more than a week. Which isn't the case here. |
@NGK02 is absolutely right, in my opinion! This issue should either be a Low one or be closed if the sponsor decides not to fix that at all. |
Why do you consider this a low-severity issue? |
This finding should deserve a medium severity given the reasonings of MatinR1. Additionally, the readme indicates the protocol's desire to override the 7 days functional inaccessibility to 12 hours. |
@MatinR1 I consider it a low because the DOS will only last for a few minutes at the absolute most since the affected party can immediately just call the regular |
I don't think that my escalation was read but @MatinR1 comments that did not escalate was? This is weird. |
This comment was marked as duplicate.
This comment was marked as duplicate.
This is a reference to permit issue tackled in Lido and why/how the team had to mitigate it lidofinance/core#803 (comment) It also highlights why this form of griefing is an issue that needs to be fixed. Good to be here guys and big kudos to everyone working together to secure the codebase. |
This comment was marked as duplicate.
This comment was marked as duplicate.
Hey all! First of all, the issue of the borrow repayment using a permit is of medium severity as it is related to grieving. Second, the escalation reason stands for calling other users, while here the Also as an answer to this sentence:
I want to add that UniswapV2 had rewarded this issue, though it was out of scope, and accepted the continuation of this architecture. It does not mean that this is not an issue. (reference) Finally, after testing the issue, I've noticed that the erc20Token.permit(msg.sender, address(this), nonce, expiry, true, v, r, s); This passes the It should be changed to: - erc20Token.permit(msg.sender, address(this), nonce, expiry, true, v, r, s);
+ erc20Token.permit(msg.sender, address(this), amount, expiry, true, v, r, s); @WangSecurity I managed to contact the dev team, but didn't get any response from them. |
As far as I understand this is invalid precisely as escalation described, as in all the examples So the original Trust EIP-2612 permission denied isn't applicable, there the prerequisite being |
@MatinR1 Please check DAI permit signature. |
I've hidden several comments because they were just repeating the information already expressed previously. I agree with the escalation and the last two comments, the report is incorrect and this issue will not occur on the union, because call to Planning to accept the escalation and invalidate the report. |
Let me give reasons why this should be considered a Medium Severity Bug
@WangSecurity I can provide POC as well if you think this is not valid then. |
@MD-YashShah1923 Here |
@dmitriia The attacker would simply call |
@MD-YashShah1923 Regarding the interest rate loss, even if you stretch the reality and have an account with a lot of debt, it will only be less than $1 for the time it takes to call the other function, let's say 10 minutes. So probably less than the additional amount of gas needed to call I will let @WangSecurity decide, but given that it's possible to call |
@twicek You are telling solution of it that use |
@MD-YashShah1923 would be very interested in your POC and can you estimate the loss (in %) here if the user repays the loan in the next block (or in the next 2-3 blocks)? |
As I have mentioned in the above comments, this leads to no loss for the users. They don't even need to generate a new signature, they can just for instance call So this takes away all the rationale for the attacker to perform that kind of an "attack". This can at maximum lead to a "DoS" of a particular signature, which is not longer than a few minutes. As per the Sherlock's rules, the medium-severity-worth DoS for it to be valid should lead to time-sensitive loses, which isn't the case for this issue. At maximum a dust amounts can be lost. @MD-YashShah1923 @WangSecurity But anyways the end "victim" user will even profit from this "attack", because he won't need to call the more gas-consuming P.S. A quasi account abstraction paymaster option, isn't it? 🙂 |
Yep, you're correct here, but since there are other functions without the permit functionality, I don't think we need to invalidate the issues with the permit by default.
Yep, what I was trying to understand is how much funds could be lost if we were forced to call the repay function a bit later, maybe it's larger than dust. Since no answer was provided to my previous comment, planning to accept the escalation and invalidate the issue. |
Sorry @WangSecurity for replying late as was busy with other task, would provide POC till EOD. |
Since still nothing is provided, the decision remains the same and will proceed with accepting the escalation and invalidating the issue tomorrow. |
There is minimum loss while repaying the borrow. |
Result: |
Escalations have been resolved successfully! Escalation status:
|
MohammedRizwan
Medium
Permit functions in
Union
contracts can be affected by DOSSummary
Permit functions in
Union
contracts can be affected by DOSVulnerability Detail
The following inscope
Union
contracts supports ERC20 permit functionality by which users could spend the tokens by signing an approval off-chain.UDai.repayBorrowWithPermit()
, , after the permit call is successful there is a call to_repayBorrowFresh()
UErc20.repayBorrowWithERC20Permit()
, , after the permit call is successful there is a call to_repayBorrowFresh()
UserManager.registerMemberWithPermit()
, , after the permit call is successful there is a call toregisterMember()
UserManagerDAI.stakeWithPermit()
, , after the permit call is successful there is a call tostake()
UserManagerERC20.stakeWithERC20Permit()
, , after the permit call is successful there is a call tostake()
The issue is that while the transactions for either of above permit functions is in mempool, anyone could extract the signature parameters from the call to front-run the transaction with direct permit call.
This issue is originally submitted by Trust security aka Trust to various on chain protocols and the issue is confirmed by reputed protocols like Open Zeppelin, AAVE, The Graph, Uniswap-V2
To understand the issue in detail, Please refer below link:
link: https://www.trust-security.xyz/post/permission-denied
Since, the protocol would be deployed on any EVM compatible chain so Ethereum mainnet has mempool with others chain too. This issue would indeed increase the approval for the user if the front-run got successful. But as the permit has already been used, the call to either of above permit functions will revert making whole transaction revert. Thus making the victim not able to make successful call to either of above permit functions to carry out borrow repay or stake or member registration.
Consider a normal scenario,
Bob wants to repay his loan with permit so he calls
UErc20.repayBorrowWithERC20Permit()
function.Alice observes the transactions in mempool and extract the signature parameters from the call to front-run the transaction with direct permit call. Alice transaction got successful due to high gas fee paid by her to minor by front running the Bob's transaction.
This action by Alice would indeed increase the approval for the Bob since the front-run got successful.
But as the permit is already been used by Alice so the call to
UErc20.repayBorrowWithERC20Permit()
will revert making whole transaction revert.Now, Bob will not able to make successful call to
UErc20.repayBorrowWithERC20Permit()
function to pay his loan by using ERC20 permit(). This is due to griefing attack by Alice. She keep repeating such attack as the intent is to grief the protocol users.Impact
Users will not be able to use the permit functions for important functions like
UDai.repayBorrowWithPermit()
,UErc20.repayBorrowWithERC20Permit()
,UserManager.registerMemberWithPermit()
,UserManagerDAI.stakeWithPermit()
andUserManagerERC20.stakeWithERC20Permit()
so these function would be practically unusable and users functionality would be affected due to above described issueCode Snippet
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/market/UDai.sol#L19
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/market/UErc20.sol#L17
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/user/UserManager.sol#L711
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/user/UserManagerDAI.sol#L29
https://github.com/sherlock-audit/2024-06-union-finance-update-2/blob/main/union-v2-contracts/contracts/user/UserManagerERC20.sol#L27
Tool used
Manual Review
Recommendation
Wrap the
permit
calls in a try catch block in above functions using permit().The text was updated successfully, but these errors were encountered: