Summary
The specification states that the contestation period in the datum of the UTxO at the head validator must stay unchanged as the state progresses from Open to Closed (Close transaction), but no such check appears to be performed in the checkClose
function of the head validator.
This would allow a malicious participant to modify the contestation deadline of the head to either allow them to fanout the head without giving another participant the chance to contest, or prevent any participant from ever redistributing the funds locked in the head via a fan-out.
Details
In the checkClose
function in Head.hs, the contestation period in the Closed state datum in the outgoing UTxO at the head validator is not checked to be unchanged, allowing the participant closing the head to choose any contestation period they would like.
https://github.com/input-output-hk/hydra/blob/master/hydra-plutus/src/Hydra/Contract/Head.hs#L284-L296
https://github.com/input-output-hk/hydra/blob/master/hydra-plutus/src/Hydra/Contract/Head.hs#L320-L323
PoC
Malicious participant creates Close transaction as normal but changes the contestation period field of the head output datum such that it does not match the contestation period specified in the Head.Open
datum of the head UTxO being spent.
Impact
A malicious participant can choose any contestation period they want in the head output Head.Closed
datum when they build the Close transaction (in the checkClose
function of the head validator), and this value is then used in the checkContest
function of the head validator to update the contestDeadline
in a contest transaction. In fact, it looks like ContestationPeriod
is a wrapper around the Integer type so can even be set to a negative number (?) which would then shift the contest deadline backwards in time. This would allow a malicious participant to modify the contestation deadline of the head to either allow them to fanout the head without giving another participant the chance to contest, or prevent any participant from reclaiming the funds from the head via a fan-out.
The former scenario would like like:
- malicious participant progresses the head from Open to Closed with a Close transaction, specifying some large negative number as the contestation period in the head output datum instead of keeping it unchanged (
malicious_cp
)
- the malicious participant submits a Contest transaction, in which the new contestation deadline
new_contest_deadline
is checked to equal current_contest_deadline + malicious_cp
, but malicious_cp
is a large negative number which means the contestation deadline will actually move backwards in time (to a point in time which has passed) instead of forwards
- the malicious participant can now immediately submit a fanout transaction without allowing other participants to contest their submitted snapshot, because the contest deadline has been set to a point in the past and so has already passed
The latter scenario is similar, but the malicious participant specifies a large positive number as the contestation period, which causes the contest deadline to be set unreachably far in the future in checkContest
, and then no participant can cause a fanout because they can only do so once the deadline has been reached, but this deadline is unreachably far in the future.
Summary
The specification states that the contestation period in the datum of the UTxO at the head validator must stay unchanged as the state progresses from Open to Closed (Close transaction), but no such check appears to be performed in the
checkClose
function of the head validator.This would allow a malicious participant to modify the contestation deadline of the head to either allow them to fanout the head without giving another participant the chance to contest, or prevent any participant from ever redistributing the funds locked in the head via a fan-out.
Details
In the
checkClose
function in Head.hs, the contestation period in the Closed state datum in the outgoing UTxO at the head validator is not checked to be unchanged, allowing the participant closing the head to choose any contestation period they would like.https://github.com/input-output-hk/hydra/blob/master/hydra-plutus/src/Hydra/Contract/Head.hs#L284-L296
https://github.com/input-output-hk/hydra/blob/master/hydra-plutus/src/Hydra/Contract/Head.hs#L320-L323
PoC
Malicious participant creates Close transaction as normal but changes the contestation period field of the head output datum such that it does not match the contestation period specified in the
Head.Open
datum of the head UTxO being spent.Impact
A malicious participant can choose any contestation period they want in the head output
Head.Closed
datum when they build the Close transaction (in thecheckClose
function of the head validator), and this value is then used in thecheckContest
function of the head validator to update thecontestDeadline
in a contest transaction. In fact, it looks likeContestationPeriod
is a wrapper around the Integer type so can even be set to a negative number (?) which would then shift the contest deadline backwards in time. This would allow a malicious participant to modify the contestation deadline of the head to either allow them to fanout the head without giving another participant the chance to contest, or prevent any participant from reclaiming the funds from the head via a fan-out.The former scenario would like like:
malicious_cp
)new_contest_deadline
is checked to equalcurrent_contest_deadline + malicious_cp
, butmalicious_cp
is a large negative number which means the contestation deadline will actually move backwards in time (to a point in time which has passed) instead of forwardsThe latter scenario is similar, but the malicious participant specifies a large positive number as the contestation period, which causes the contest deadline to be set unreachably far in the future in
checkContest
, and then no participant can cause a fanout because they can only do so once the deadline has been reached, but this deadline is unreachably far in the future.