Open code423n4 opened 1 year ago
See #218 and #107, separate for now
Technically the described attack would work.
It is also related to the trust assumption between the sender an receiver. Which are anyway given in a certain form.
I am unsure about the proposed solutions. Currently, we only store the latest dripsHistory hash on-chain. For allowing to squeeze until a specific timestamp, it might be necessary to have the full list of historic hashes on-chain.
[disagree with severity: QA] This attack is in fact possible, but it only allows postponing collecting funds until the end of the cycle. The proposed solution would probably require a lot of storage, so it's probably not worth introducing.
CodeSandwich marked the issue as disagree with severity
I believe this boils down to the same underlying issue highlighted in #107
This is basically the other side of #107, I'll think about it, but due to logical equivalency and the underlying issue being the same, I think I'll duplicate this one as well
GalloDaSballo marked the issue as duplicate of #201
GalloDaSballo marked the issue as not a duplicate
During Post-Judging QA it was brought to my attention that this is a separate finding, have looked at this one again
GalloDaSballo marked the issue as satisfactory
In order to judge this issue I spoke with 4 other judges as well as the Sponsor.
This is a difficult decision because of the unclear expectations as to whether the sender is bening towards the receiver or not.
Because of the uncertainty, and the possibility of performing the grief, the finding is valid.
The issue is in terms of determining it's severity.
One of the most interesting arguments is the idea that "the attacker doesn't gain anything", which can be falsified in scenarios in which squeezing would have helped reach a threshold of tokens in circulation, out of vesting or for similar purposes.
If we try hard enough, through multiple people's effort, we can come up with a scenario in which squeezing could make a difference between having enough votes for a Governance Operation, or could offer enough collateral to avoid a liquidation or some level of risk.
Those scenarios, while unlikely, can help discredit the idea that "the attacker doesn't gain anything".
On the other hand, we must acknowledge that the attack / griefing, is limited:
sender
is the only privileged account that can perform the griefThese can be viewed as additional external requirements, which reduce the impact / likelihood of the finding
In spite of the external requirements, the finding is showing how the functionality of Squeezing can be denied by the sender.
I believe that if anybody could grief squeezing, we would not hesitate in awarding Medium Severity and perhaps we'd be discussing around Med / High.
However, in this case, the only account that can perform the grief is the sender.
At the same time, the goal of the system is to allow Squeezing, which per the discussion above, given the finding can be prevented until a drip has moved to a newer crycle.
I went into the tests and wrote the following illustratory cases
function testSenderCanStopAfter() public {
uint128 amt = cycleSecs;
setDrips(sender, 0, amt, recv(receiver, 1), cycleSecs);
DripsHistory[] memory history = hist(sender);
skip(1);
squeezeDrips(receiver, sender, history, 1);
setDrips(sender, amt - 1, 0, recv(receiver, 1), 0);
// Squeeze again
DripsHistory[] memory history2 = hist(history, sender);
squeezeDrips(receiver, sender, history2, 0);
skipToCycleEnd();
receiveDrips(receiver, 0);
}
function testSenderCannotChangeTheirMind() public {
uint128 amt = cycleSecs;
setDrips(sender, 0, amt, recv(receiver, 1), cycleSecs);
DripsHistory[] memory history = hist(sender);
skip(1);
setDrips(sender, amt - 1, 0, recv(receiver, 1), 0);
// Squeeze First time
DripsHistory[] memory history2 = hist(history, sender);
squeezeDrips(receiver, sender, history2, 1);
skipToCycleEnd();
receiveDrips(receiver, 0);
}
Ultimately we can see that what is owed to the recipient can never be taken back, however the sender can, through the grief shown in the above finding, prevent the tokens from being received until the end.
Given the information above, being mindful of:
I agree with Medium Severity
GalloDaSballo marked the issue as selected for report
GalloDaSballo marked the issue as primary issue
Lines of code
https://github.com/code-423n4/2023-01-drips/blob/9fd776b50f4be23ca038b1d0426e63a69c7a511d/src/Drips.sol#L411 https://github.com/code-423n4/2023-01-drips/blob/9fd776b50f4be23ca038b1d0426e63a69c7a511d/src/Drips.sol#L461
Vulnerability details
Squeezing drips from a sender requires providing the sequence of drips configurations (see NatSpec description in L337-L338):
The provided history entries are hashed and verified against the sender's
dripsHistoryHash
.However, the sender can prevent a receiver from squeezing drips by front-running the squeeze transaction and adding a new configuration. Adding a new configuration updates the current
dripsHistoryHash
and invalidates thehistoryHash
provided by the receiver when squeezing. The receiver will then fail the drips history verification in L461 and the squeeze will fail.Impact
A sender can prevent its drip receivers from squeezing by front-running the squeeze transaction and adding a new configuration.
Proof of Concept
Drips.sol#L411
Drips.sol#L461
Tools Used
Manual review
Recommended mitigation steps
Consider allowing a receiver to squeeze drips from a sender up until the current timestamp.