Summary
Users send the UTxOs they wish to commit into the Hydra head first to the commit
validator, where they remain until they are either collected into the head
validator or the protocol initialisation is aborted and the value in the committed UTxOs is returned to the users who committed them.
The commit
validator contains a flawed check when the ViaAbort
redeemer is used, which allows any user to spend any UTxO which is at the validator arbitrarily, meaning an attacker can steal the funds that users are trying to commit into the head validator. The intended behaviour is that the funds must be returned to the user which committed the funds and can only be performed by a participant of the head.
The initial
validator also is similarly affected as the same flawed check is performed for the ViaAbort
redeemer.
Details
UTxOs at the commit
validator can be spent with either the ViaAbort
redeemer, used when the protocol initialisation is being aborted, or the ViaCollectCom
redeemer, used when all the parties committed UTxOs are being collected into the head
validator.
The commit
validator performs a single check when the ViaAbort
redeemer is used: check that the head ID state token is burnt. The intention of this check is that if we ensure the head state token is burnt, then the transaction must also spend an input at the head validator with the Abort
redeemer, and the head validator will have performed the checks that the committed value is returned to the user which committed.
https://github.com/input-output-hk/hydra/blob/master/hydra-plutus/src/Hydra/Contract/Commit.hs#L94-L97
The check that the ST is burned is done via the mustBurnST
function.
https://github.com/input-output-hk/hydra/blob/master/hydra-plutus/src/Hydra/Contract/Util.hs#L32-L42
This function likely should only return True if the txmint field contains headCurrencySymbol -> "HydraHeadV1" -> (-1)
, but on line 37 it returns True if no token kinds of the headCurrencySymbol are found in the txmint field, and on line 40 it returns True if some tokens kinds of headCurrencySymbol are found in the txmint field but no token named "HydraHeadV1" is found. This check currently will return True if the txmint field contains no entries.
This means the commit
validator will execute successfully when using the ViaAbort
redeemer without needing to burn the ST token, which means we can avoid executing the head
validator and therefore avoid executing the checks which ensure the funds in the committed UTxOs are returned to the correct owners.
The initial
validator also is affected as the same check using mustBurnST
is performed for the ViaAbort
redeemer, but the impact is lesser because there should not be significant funds at the initial
validator. The impact for the initial
validator is more like denial of service, because an attacker could prevent a Hydra head from being successfully created because they can abort any head which is in the process of being initialised, despite them not needing to being a participant of the head.
PoC
Setup:
- A user has sent a UTxO to the
commit
validator.
Then, create a transaction with the properties:
- Spend a UTxO at the
commit
validator as an input, using the ViaAbort
redeemer
- Leave the txmint field empty
- Create any output such that the preservation of value rule is maintained (for example send the funds from the UTxO at the
commit
validator to any address you choose)
Impact
Critical
An attacker can steal any funds that user's try to commit into a Hydra head. Also, an attacker can prevent any Hydra head from being successfully opened.
It does not allow an attacker to take funds which have been successfully collected into and currently reside in the head
validator.
Summary
Users send the UTxOs they wish to commit into the Hydra head first to the
commit
validator, where they remain until they are either collected into thehead
validator or the protocol initialisation is aborted and the value in the committed UTxOs is returned to the users who committed them.The
commit
validator contains a flawed check when theViaAbort
redeemer is used, which allows any user to spend any UTxO which is at the validator arbitrarily, meaning an attacker can steal the funds that users are trying to commit into the head validator. The intended behaviour is that the funds must be returned to the user which committed the funds and can only be performed by a participant of the head.The
initial
validator also is similarly affected as the same flawed check is performed for theViaAbort
redeemer.Details
UTxOs at the
commit
validator can be spent with either theViaAbort
redeemer, used when the protocol initialisation is being aborted, or theViaCollectCom
redeemer, used when all the parties committed UTxOs are being collected into thehead
validator.The
commit
validator performs a single check when theViaAbort
redeemer is used: check that the head ID state token is burnt. The intention of this check is that if we ensure the head state token is burnt, then the transaction must also spend an input at the head validator with theAbort
redeemer, and the head validator will have performed the checks that the committed value is returned to the user which committed.https://github.com/input-output-hk/hydra/blob/master/hydra-plutus/src/Hydra/Contract/Commit.hs#L94-L97
The check that the ST is burned is done via the
mustBurnST
function.https://github.com/input-output-hk/hydra/blob/master/hydra-plutus/src/Hydra/Contract/Util.hs#L32-L42
This function likely should only return True if the txmint field contains
headCurrencySymbol -> "HydraHeadV1" -> (-1)
, but on line 37 it returns True if no token kinds of the headCurrencySymbol are found in the txmint field, and on line 40 it returns True if some tokens kinds of headCurrencySymbol are found in the txmint field but no token named "HydraHeadV1" is found. This check currently will return True if the txmint field contains no entries.This means the
commit
validator will execute successfully when using theViaAbort
redeemer without needing to burn the ST token, which means we can avoid executing thehead
validator and therefore avoid executing the checks which ensure the funds in the committed UTxOs are returned to the correct owners.The
initial
validator also is affected as the same check usingmustBurnST
is performed for theViaAbort
redeemer, but the impact is lesser because there should not be significant funds at theinitial
validator. The impact for theinitial
validator is more like denial of service, because an attacker could prevent a Hydra head from being successfully created because they can abort any head which is in the process of being initialised, despite them not needing to being a participant of the head.PoC
Setup:
commit
validator.Then, create a transaction with the properties:
commit
validator as an input, using theViaAbort
redeemercommit
validator to any address you choose)Impact
Critical
An attacker can steal any funds that user's try to commit into a Hydra head. Also, an attacker can prevent any Hydra head from being successfully opened.
It does not allow an attacker to take funds which have been successfully collected into and currently reside in the
head
validator.