Closed sherlock-admin3 closed 3 weeks ago
the issue seems like a best practice advice, doesn't deserve medium severity.
@0xsimao Even tho I said I wouldn't step in here again, but I have to because all your comments and the validity of this issue is based on Chainlink being cursed
And finally the admin expects refunds to be always possible, which is not the case due to Chainlink being cursed.
This protocol is cross-chain, so any action on the tickets manager on the Avalench chain should notify the PrizeManager on the Ethereum destination chain. If Chainhainlink is cursed(supposing so, even if it never happened), it makes sense to stop all the actions that require cross-chain messages, even canceling the raffle because the cancel requires notifying the prizeManager
to unlock the prize.
So, the admin expecting _refunds to be always possible_
and the contest README saying that *Participants in a raffle that got cancelled can always get refunded*
is when the protocol is under normal behavior, it does not apply when cross-chain messaging is unsafe due to Chainlink being cursed.
Again, read the README word by word:
Participants in a raffle that got cancelled can always get refunded
The invariant is that users should always get refunded for raffles that GOT CANELLED. You can't and it is unsafe to cancel raffles if Chainlink is cursed. So, the invariant is NOT broken
The fix proposed diverges from the protocol's intended behavior. The fix suggests not to notify the prizeManager
on the destination chain when canceling a raffle. This is incorrect, when canceling a raffle, the prizeManager
on the destination chain should be notified to unlock the prizes. So, following your fix, if Chainlink is cursed, canceling the raffle will succeed on the source chain BUT the prizeManager
will not be notified on the destination chain and the prize will not be unlocked. Something that is incorrect from the protocol's perspective
This protocol is cross-chain, so any action on the tickets manager on the Avalench chain should notify the PrizeManager on the Ethereum destination chain. If Chainhainlink is cursed(supposing so, even if it never happened), it makes sense to stop all the actions that require cross-chain messages, even canceling the raffle because the cancel requires notifying the prizeManager to unlock the prize.
What makes sense is what is in the readme, that is, users always get their refunds. The admin can claim it later, when Chainlink is no longer cursed.
So, the admin expecting refunds to be always possible and the contest README saying that Participants in a raffle that got cancelled can always get refunded is when the protocol is under normal behavior, it does not apply when cross-chain messaging is unsafe due to Chainlink being cursed.
Why would that be if it's possible to issue refunds safely when Chainlink is cursed? And the admin can get the funds after Chainlink is no longer cursed.
The invariant is that users should always get refunded for raffles that GOT CANELLED. You can't and it is unsafe to cancel raffles if Chainlink is cursed. So, the invariant is NOT broken
We have discussed this, the statement assumes that raffles can be cancelled. The reason for cancelling raffles is not reaching the minimum tickets. So whenever the minimum tickets are not reached, the raffle must be cancelled and users should get their refunds. Naturally we can not give refunds if the round can not even be cancelled. The main premise is broken, so the statement is also broken. Nothing is unsafe, with the fix, users get their refunds and the admin claims the prize later.
The fix proposed diverges from the protocol's intended behavior. The fix suggests not to notify the prizeManager on the destination chain when canceling a raffle. This is incorrect, when canceling a raffle, the prizeManager on the destination chain should be notified to unlock the prizes. So, following your fix, if Chainlink is cursed, canceling the raffle will succeed on the source chain BUT the prizeManager will not be notified on the destination chain and the prize will not be unlocked. Something that is incorrect from the protocol's perspective
False. With the fix, users always get their refunds and the admin is guaranteed to claim the prize later, when Chainlink is not cursed. The difference the fix makes is users can always get their refunds, the admin will get the prize at the same time it would as in the current code (has to wait for Chainlink to not be cursed). This does not deviate from the protocol's intention at all.
Participants in a raffle that got cancelled can always get refunded
If, due to this issue, the raffle can be cancelled, the above statement is not broken. It's not about the raffle being cancelled under any conditions or certain conditions. After the Chainlink issue is resolved, the participants can easily get their refund. I don't see "always" as "at any point at a time", it's about getting the refund for any raffle that got cancelled and this is not broken, since in the end the user can still get their refunds.
This issue doesn't break the README statement and doesn't qualify for the DOS requirements to be considered a medium-severity issue. Planning to accept the escalation and invalidate the issue.
@WangSecurity the docs don't say that the issue will be resolved in less than 1 week.
And the temporal aspect of always is being ignored, could you explain why this is so? The readme is the source of truth and the word 'always' has a temporal meaning, not only certainty, so the issue is valid.
Definition of always
every time or all the time
So a few days where it is false does not match the definition of always.
Definition of time from the same dictionary
the part of existence that is measured in minutes, days, years, etc., or this process considered as a whole
So a few days where it is false does match the definition of always, as long as the process considered as a whole is still completed
@WangSecurity I wanna add one more thing to your point here:
If, due to this issue, the raffle can be cancelled, the above statement is not broken. It's not about the raffle being cancelled under any conditions or certain conditions.
This protocol is a cross-chain protocol. When cancelling the raffle on the source chain, the destination chain must be informed of such action to unlock the prize. So, even if the Chainlink router is cursed, it is not by protocol design to cancel the raffle on the source chain and only notify the destination chain when the router is live again, as this report suggests.
So, if the chainlink router is DoSed, all actions must stop and everything can be finalized after the router is live again. Participants will still be able to cancel the raffle and get refunded when the router is live, with no loss of funds, and no DoS of the protocol either. This protocol should not function if the CCIP router is down.
So, if the chainlink router is DoSed, all actions must stop and everything can be finalized after the router is live again.
This is false as per the readme, users should always get their refunds.
So, if the chainlink router is DoSed, all actions must stop and everything can be finalized after the router is live again.
This is false as per the readme, users should always get their refunds.
@0xsimao I’ve explained this point multiple times during our discussion, and it seems to be the key reason for the extended debate.
You are misinterpreting the contest README: Participants in a raffle that got cancelled can always get refunded. This invariant is stating that users should get refunded for CANCELLED raffles. Since raffle cancellation and winner propagation rely on cross-chain communication, if the CCIP router is subject to a DoS, the cancellation should not proceed. As a result, the statement in the README remains intact and unbroken because there is no cancelled raffle.
@Brivan-26
The readme says
Participants in a raffle that got cancelled can always get refunded
which assumes rounds can be cancelled, which is not true due to the cursed modifier. The base assumption is broken, so the statement is also broken. The conceptual reason for the round being cancelled is there, which is the minimum tickets not being reached, so the round should be cancelled. If it is not cancelled users can not get their refunds.
Since raffle cancellation and winner propagation rely on cross-chain communication, if the CCIP router is subject to a DoS, the cancellation should not proceed. As a result, the statement in the README remains intact and unbroken because there is no cancelled raffle.
Again, the readme is clear and users can always be refunded. So this means the protocol should proceed for the users refunds, not that is should be halted.
the docs don't say that the issue will be resolved in less than 1 week
I understand, but based on the historical evidence, these issues were resolved in less than a week.
As I've said previously, the README statement is not about users being able to get a refund at any point in time; it's about users being able to get the funds for any cancelled raffle they've participated in. I see that it may be confusing, but still, this invariant doesn't refer to "any point in time".
Hence, my decision remains the same as previously: the issue doesn't break README and doesn't qualify for DOS requirements. Hence, planning to accept the escalation and invalidate the issue.
Hey @WangSecurity is there any reason why is this escalation not accepted yet, and the finding invalidated. It has been 2 days since your comment, and no one is disputing anything publicly?
I was checking some things before resolving this.
Result: Invalid Has duplicates
0x73696d616f
Medium
CCIPClient
whenHealthy
modifier will lead to stuckETH
due to DoSing claim and cancelSummary
CCIPClient
has awhenHealthy
modifier in theccipSend()
function, which means it can DoS_sendCCIPMessage()
calls inWinnablesTicketManager
. This would be particularly harmful in several scenarios:CANCELED
and allows users to claim refunds, but also sends a message toWinnablesPrizeManager
to allow the admins to get their funds back. If the router is not healthy, it will revert. This procedure should be perfomed in a 2 step such that users can get their refunds right away, as they don't need to wait for the ccip router to work.WinnablesTicketManager::propagateRaffleWinner()
reverts when calling_sendCCIPMessage()
. This means that the protocol can never claim itsETH
although the cross chain message was not required to be successful. A two step procedure would also fix this.Scenario 1 breaks the specification in the readme
Root Cause
The Chainlink Router has the
whenHealthy
modifier inccipSend()
, called in_sendCCIPMessage()
, which DoSes the router as can be seen in the code linked above in lines 293-296.WinnablesTicketManager
does not deal with thenotHealthy
modifier.Internal pre-conditions
None.
External pre-conditions
Chainlink pauses the Router.
Attack Path
The examples are given: A
WinnablesTicketManager::buyTickets()
.B
WinnablesTicketManager::buyTickets()
.ETH
due to point 2 even though the cross chain message was not required.Impact
In scenario A, users can not claim their refunds until the router is back up. In B, the protocol can not claim the ETH back even though it could be safely retrieved.
PoC
Check the mentioned Chainlink router links and the fact that the code never checks if the router is not healthy before calling
_sendCCIPMessage()
.Mitigation
The
WinnablesTicketManager::cancelRaffle()
andWinnablesTicketManager::propagateRaffleWinner()
functions should be split into 2 separate steps, to always make sure users or the protocol can get their funds.