Open sherlock-admin2 opened 1 month ago
1 comment(s) were left on this issue during the judging contest.
infect3d commented:
invalid__ only affect bots that deliberately chose to set code inside the fallback function
The zkSync doc link provided in the issue does not seem to have information on this behaviour anymore. Is there an updated link on the issue?
request poc
PoC requested from @elhajin
Requests remaining: 1
Escalate
This submission make the assumption that the caller will set code in their callback to process received ETH. This pose the assumption that those callers will not be aware of the limitation of the transfer/send behavior on these chains. Setting code in the callback isn't required at all for the caller. By simply not setting code in their callback, the issue disappear, thus this is a user error and not a vulnerability of the codebase, but rather a proposition of improvement of the implemented mechanism.
from the doc: https://docs.zksync.io/build/developer-reference/best-practices#use-call-over-send-or-transfer
Avoid using payable(addr).send(x)/payable(addr).transfer(x) because the 2300 gas stipend may not be enough for such calls, especially if it involves state changes that require a large amount of L2 gas for data. Instead, we recommend using call.
Escalate
This submission make the assumption that the caller will set code in their callback to process received ETH. This pose the assumption that those callers will not be aware of the limitation of the transfer/send behavior on these chains. Setting code in the callback isn't required at all for the caller. By simply not setting code in their callback, the issue disappear, thus this is a user error and not a vulnerability of the codebase, but rather a proposition of improvement of the implemented mechanism.
from the doc: https://docs.zksync.io/build/developer-reference/best-practices#use-call-over-send-or-transfer
Avoid using payable(addr).send(x)/payable(addr).transfer(x) because the 2300 gas stipend may not be enough for such calls, especially if it involves state changes that require a large amount of L2 gas for data. Instead, we recommend using call.
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.
I wouldn't call this user error because any address can be used to transfer funds to creator. Also it does not just affect caller with no code and there is clear evidence from the sponsor acknowledgement and lack of details in contest that the sponsor wasn't aware of this issue.
Disagreeing with the Escalation
By simply not setting code in their callback, the issue disappears.
Removing the callbacks from the caller will not solve this issue.
The core issue is not related to the use of code in the callback; rather, it is a limitation of the ZkSync chain. The core issue arises due to the dynamic gas measurement followed in ZkSync.
ZkSync usually requires more than 2300 gas to process transfer()
/send()
functions. Therefore, the withdraw()
function will always revert due to the lack of enough gas to process transfer()
on ZkSync.
ZkSync explicitly mentions this in their security and best practice documentation:
Avoid using payable(addr).send(x)/payable(addr).transfer(x) because the 2300 gas stipend may not be enough for such calls.
The situation worsens if there are any callback functionalities in the caller.
This is a known issue in ZkSync, as evidenced by previous occurrences in other protocols:
Note: Please see issues #24 and #139, which explain the issue in detail.
Fair enough, I wasn't able to find that even without callback execution it could spend more than 2300. Sorry for the misunderstanding, and thanks for the detailed explanation!
In addition to my previous comment:
This issue causes a loss of ETH in ZkSync.
According to Sherlock's docs, this issue should be considered as valid HIGH:
IV. How to identify a high issue:
- Definite loss of funds without (extensive) limitations of external conditions.
Please consider upgrading the severity to HIGH.
Please find my thoughts on the duplicates below:
Since the escalator agrees with the other side (correct me if it's wrong) and based on the discussion above, I believe this issue should remain as it is. Planning to reject the escalation.
Is there a specific number of ETH that has to be transferred in that case, or it can be as small as 1 wei? And as I understand there's still a possibility the transfer
would work correctly?
Rng draw rewards are very low ( <0.0001 WETH), as it can be seen on the Pool Together dashboard: https://analytics.cabana.fi/optimism The loss that will be experienced by rng drawer isn't large enough to be an argument for a high severity imo
I agree with the comment above, I believe it's a small value and only caused on one chain, hence, I believe medium is more appropriate.
The decision remains the same, planning to reject the escalation and leave the issue as it is.
Result: Medium Has duplicates
The protocol team fixed this issue in the following PRs/commits: https://github.com/GenerationSoftware/pt-v5-rng-witnet/pull/9
elhaj
medium
Potential ETH Loss Due to transfer Usage in Requestor Contract on
zkSync
Summary
transfer
to sendETH
which has the risk that it will not work if the gas cost increases/decrease(low Likelihood), but it is highly likely to fail onzkSync
due to gas limits. This may make users'ETH
irretrievable.Vulnerability Detail
Users (or bots) interact with RngWitnet to request a random number and start a draw in the
DrawManager
contract. To generate a random number, users must provide someETH
that will be sent to WitnetRandomness to generate the random number.The
ETH
sent with the transaction may or may not be used (if there is already a request in the same block, it won't be used). Any remaining or unusedETH
will be sent to Requestor, so the user can withdraw it later.The issue is that the
withdraw
function in theRequestor
contract usestransfer
to sendETH
to the receiver. This may lead to users being unable to withdraw their funds .The protocol will be deployed on different chains including
zkSync
, onzkSync
the use oftransfer
can lead to issues, as seen with 921 ETH Stuck in zkSync Era.since it has a fixed amount of gas23000
which won't be anough in some cases even to send eth to anEOA
, It is explicitly mentioned in their docs to not use thetransfer
method to sendETH
here.Impact
ETH
may be irretrievable or undelivered, especially on zkSync, due to the use of.transfer
.Code Snippet
Tool used
Manual Review , Foundry Testing
Recommendation
.call()
forETH
transfer.