#37718 [BC-High] Key rotations bricks the system due to incorrect `aggregate_key` being used to spend the `peg UTXO` when signing a sweep transaction
Submitted on Dec 13th 2024 at 08:31:21 UTC by @n4nika for Attackathon | Stacks
Report ID: #37718
Report Type: Blockchain/DLT
Report severity: High
Target: https://github.com/stacks-network/sbtc/tree/immunefi_attackaton_0.9/signer
Impacts:
Network not being able to confirm new transactions (total network shutdown)
Description
Summary
When the coordinator gets the signatures to spend the previous peg-UTXO
, they need to pass the aggregate_key
which matches the key of that UTXO's key-only spendable taproot output. Currently this is not the case if we rotated the keys in the current signing round. This causes the coordinator to get a signature for the sweep transaction which cannot actually spend it. Since there is no programmed fallback to fix this, this will completely shutdown the system.
Finding Description
In the coordinator we have the following flow:
get requests from
emily
deploy smart contracts if needed
handle key rotation
get pre-signature (just pre-validation)
handle
sweep
transactionshandle sBTC deposit transactions (
s-deposit
) (these mint sBTC)get signatures from signers
submit the TX to Stacks
If we look at the code, we see that the newly gotten aggregate_key
is used if we just rotated the keys:
At [1]
, we pass it to the function handling the sweep transactions (which includes handling of the peg UTXO
).
That function then calls sign_and_broadcast
which then coordinates signing rounds in order to spend the peg UTXO
and all user deposits. What is important here, is the signing of the peg UTXO
:
At [2]
we create the state machine used for signing with the aggregate_key
and request signatures using that state machine at [3]
.
Scenario
This becomes an issue if we rotate the keys:
we have an
aggregate_key
(keyA
) which we use to signpeg UTXOs
. This means all our newly generated UTXOs can only be spent withkeyA
!we now rotate our keys, generating a new key (
keyB
)since we use
keyB
insign_and_broadcast
now, the resulting signature will NOT be able to spend the previousUTXO
since it is only spendable withkeyA
!
Impact
This will cause a full system halt since we cannot execute new sweep transactions and our previous peg UTXO
is locked until we execute a signer upgrade.
Mitigation
In order to fix this, I would recommend getting the needed aggregate_key
from the previous peg UTXO
itself. This should work since signers are still able to sign for old aggregate_key
s even after a rotation (according to the team).
Proof of Concept
Note to immunefi
This issue was discussed in discord and I was asked by @djordon to submit it explicitly without the requirement to write a PoC
Was this helpful?