Summary
In normal use the participation tokens of a Hydra head remain under the control of the Hydra validators from the point they are minted until they are burned. Because of this, the validators can trust that a UTxO containing a PT has been progressed through the Hydra validators which come before it and been subject to the constraints and checks performed by the validators which the PT has passed through.
For example, the commit
validator assumes that a UTxO residing at the commit
validator containing a PT can only have progressed from the initial
validator to the UTxO at the commit
validator if the transaction creating the UTxO passed the checks enforced by the initial
validator. In this particular case, the commit
validator knows that for a UTxO containing a PT at the commit
validator that specifies a reference to a committed UTxO commit_ref
in its datum, the initial
validator will have checked that the participant really did commit that UTxO.
A UTxO containing a PT and its data is seen as trusted, because it has been progressed through the Hydra validators and subject to their checks. Therefore if a malicious user can extract a PT from the control of the Hydra validators this trust assumption is broken, because it is no longer true that a UTxO containing a PT was subject to the checks of the Hydra validators, and the malicious user can place the PT in any UTxO with any datum they like attached at any address they wish. For example, the attacker can put the PT in a UTxO at the commit
validator stating in the datum that they committed a particular UTxO, when in reality they did not really commit
this UTxO which was possible because this was not checked by the initial
validator, as the PT was moved from the control of the attacker to the commit
validator instead of from the initial
contract.
It is possible for a malicious head initialiser to extract one or more PTs for the head they are initialising due to incorrect data validation logic in the head token minting policy which then results in an flawed check for burning the head ST in the initial
validator.
Details
It is possible for a malicious head initialiser to extract one or more PTs for the head they are initialising. First, in the head-initialisation transaction the attacker specifies a policy they control (attacker_cid
) instead of the real head ID policy in the datum of one of the outputs at the initial
validator.
This is possible because it is not checked in HeadTokens.hs that the datums of the outputs at the initial
validator are equal to the real head ID, and it is also not checked in the off-chain code.
The UTxO resides at the initial
validator and contains a PT for the real head ID. It is possible to spend UTxOs at the initial
contract using one of two redeemers, viaAbort
and viaCommit
. If the UTxO is being redeemed using viaAbort
then the only check performed is that the state token for the head is burned in the transaction, as this will mean the head
validator enforces a number of rules (such as the PTs being burned).
https://github.com/input-output-hk/hydra/blob/1e13b60a7b21c5ccd6c36e3cf220547f5d443cef/hydra-plutus/src/Hydra/Contract/Initial.hs#L84-L91
This check that the state token is burned takes the head ID from the UTxO datum, and checks that the txmint field contains datum.head_id -> "HydraHeadV1" -> (-1)
, but the attacker set the head ID in the datum to a policy they control instead of the real head ID; that is, datum.head_id = attacker_cid
. This means that the only check done by viaAbort
is that the txmint field contains attacker_cid -> "HydraHeadV1" -> (-1)
, which the attacker can satisfy because they control attacker_cid
and can have previously minted a token named "HydraHeadV1"
that they can burn in the transaction.
This means the attacker can spend the UTxO at the initial
validator containing a PT for the head by burning the "fake" head ST they minted previously, and bypass the usual checks that would be performed by the head
validator when burning the real head ST - in particular they can move the PT out of control of the Hydra validators and into their own control/wallet.
PoC
- Attacker creates a minting policy (
attacker_cid
) and mints the token named "HydraHeadV1" under that policy.
- Attacker creates an
InitTx
to initialise a Hydra head with head_cid
, but in one of the outputs (malicious_output
) at the initial
contract they specify attacker_cid
in the datum instead of head_cid
.
- Attacker creates a transaction which:
- spends
malicious_output
with the ViaAbort
redeemer
- burns
1
of the token they minted earlier (txmint field contains attacker_cid -> "HydraHeadV1" -> (-1)
)
- sends the PT for
head_cid
contained in malicious_output
to their own wallet (or anywhere they wish)
The attacker then has control of a PT for head_cid
.
Impact
During the Initial
state of the protocol, if the malicious initialiser removes a PT from the Hydra scripts it becomes impossible for any other participant to reclaim any funds they have attempted to commit into the head, as to do so the Abort transaction must burn all the PTs for the head, but they cannot burn the PT which the attacker controls and so cannot satisfy this requirement. That means the initialiser can lock the other participants committed funds forever or until they choose to return the PT (ransom).
The malicious initialiser can also use the PT to spoof that they have committed a particular TxO when progressing the head into the Open
state. For example, they could say they committed a TxO residing at their address containing 100 ADA, but in fact this 100 ADA was not moved into the head, and thus in order for an other participant to perform the fanout they will be forced to pay the attacker the 100 ADA out of their own funds, as the fanout transaction must pay all the committed TxOs (even though the attacker did not really commit that TxO). They can do this by placing the PT in a UTxO with a well-formed Commit
datum with whatever contents they like, then use this UTxO in the collectCom
transaction.
There may be other possible ways to abuse having control of a PT.
Summary
In normal use the participation tokens of a Hydra head remain under the control of the Hydra validators from the point they are minted until they are burned. Because of this, the validators can trust that a UTxO containing a PT has been progressed through the Hydra validators which come before it and been subject to the constraints and checks performed by the validators which the PT has passed through.
For example, the
commit
validator assumes that a UTxO residing at thecommit
validator containing a PT can only have progressed from theinitial
validator to the UTxO at thecommit
validator if the transaction creating the UTxO passed the checks enforced by theinitial
validator. In this particular case, thecommit
validator knows that for a UTxO containing a PT at thecommit
validator that specifies a reference to a committed UTxOcommit_ref
in its datum, theinitial
validator will have checked that the participant really did commit that UTxO.A UTxO containing a PT and its data is seen as trusted, because it has been progressed through the Hydra validators and subject to their checks. Therefore if a malicious user can extract a PT from the control of the Hydra validators this trust assumption is broken, because it is no longer true that a UTxO containing a PT was subject to the checks of the Hydra validators, and the malicious user can place the PT in any UTxO with any datum they like attached at any address they wish. For example, the attacker can put the PT in a UTxO at the
commit
validator stating in the datum that they committed a particular UTxO, when in reality they did not reallycommit
this UTxO which was possible because this was not checked by theinitial
validator, as the PT was moved from the control of the attacker to thecommit
validator instead of from theinitial
contract.It is possible for a malicious head initialiser to extract one or more PTs for the head they are initialising due to incorrect data validation logic in the head token minting policy which then results in an flawed check for burning the head ST in the
initial
validator.Details
It is possible for a malicious head initialiser to extract one or more PTs for the head they are initialising. First, in the head-initialisation transaction the attacker specifies a policy they control (
attacker_cid
) instead of the real head ID policy in the datum of one of the outputs at theinitial
validator.This is possible because it is not checked in HeadTokens.hs that the datums of the outputs at the
initial
validator are equal to the real head ID, and it is also not checked in the off-chain code.The UTxO resides at the
initial
validator and contains a PT for the real head ID. It is possible to spend UTxOs at theinitial
contract using one of two redeemers,viaAbort
andviaCommit
. If the UTxO is being redeemed usingviaAbort
then the only check performed is that the state token for the head is burned in the transaction, as this will mean thehead
validator enforces a number of rules (such as the PTs being burned).https://github.com/input-output-hk/hydra/blob/1e13b60a7b21c5ccd6c36e3cf220547f5d443cef/hydra-plutus/src/Hydra/Contract/Initial.hs#L84-L91
This check that the state token is burned takes the head ID from the UTxO datum, and checks that the txmint field contains
datum.head_id -> "HydraHeadV1" -> (-1)
, but the attacker set the head ID in the datum to a policy they control instead of the real head ID; that is,datum.head_id = attacker_cid
. This means that the only check done byviaAbort
is that the txmint field containsattacker_cid -> "HydraHeadV1" -> (-1)
, which the attacker can satisfy because they controlattacker_cid
and can have previously minted a token named"HydraHeadV1"
that they can burn in the transaction.This means the attacker can spend the UTxO at the
initial
validator containing a PT for the head by burning the "fake" head ST they minted previously, and bypass the usual checks that would be performed by thehead
validator when burning the real head ST - in particular they can move the PT out of control of the Hydra validators and into their own control/wallet.PoC
attacker_cid
) and mints the token named "HydraHeadV1" under that policy.InitTx
to initialise a Hydra head withhead_cid
, but in one of the outputs (malicious_output
) at theinitial
contract they specifyattacker_cid
in the datum instead ofhead_cid
.malicious_output
with theViaAbort
redeemer1
of the token they minted earlier (txmint field containsattacker_cid -> "HydraHeadV1" -> (-1)
)head_cid
contained inmalicious_output
to their own wallet (or anywhere they wish)The attacker then has control of a PT for
head_cid
.Impact
During the
Initial
state of the protocol, if the malicious initialiser removes a PT from the Hydra scripts it becomes impossible for any other participant to reclaim any funds they have attempted to commit into the head, as to do so the Abort transaction must burn all the PTs for the head, but they cannot burn the PT which the attacker controls and so cannot satisfy this requirement. That means the initialiser can lock the other participants committed funds forever or until they choose to return the PT (ransom).The malicious initialiser can also use the PT to spoof that they have committed a particular TxO when progressing the head into the
Open
state. For example, they could say they committed a TxO residing at their address containing 100 ADA, but in fact this 100 ADA was not moved into the head, and thus in order for an other participant to perform the fanout they will be forced to pay the attacker the 100 ADA out of their own funds, as the fanout transaction must pay all the committed TxOs (even though the attacker did not really commit that TxO). They can do this by placing the PT in a UTxO with a well-formedCommit
datum with whatever contents they like, then use this UTxO in thecollectCom
transaction.There may be other possible ways to abuse having control of a PT.