Keyless Anchors Are Vulnerable To Replacement Cycling Attacks
3 messages, 2 to 27 Aug 2024. Started by Peter Todd.
Peter Todd, Keagan McClelland, Antoine Riard
This feels like someone should have published it before. But I can't find an obvious citation (eg in any of the documentation around keyless ephemeral anchors), so I'll publish one here. Maybe I'm the first to point this out explicitly? Probably not; I'd appreciate an earlier citation if one exists.
tl;dr: _Anyone_ can do a replacement cycling attack on transactions where fees are paid via CPFP via keyless anchors and similar outputs that a third-party can double-spend. Secondly, for attackers who were already planning on making a transaction with a higher total fee and total fee-rate than the target, this attack is almost free.
# The Attack
Suppose that Alice has created a 2 transaction package consisting of low-fee or zero-fee transaction A, whose fees are CPFP paid via a keyless ephemeral anchor spent by transaction B. For B to pay fees, obviously it must spend a second transaction output.
Mallory can cycle A and B out of mempools by broadcasting transaction B2, spending his own output and the keyless ephemeral anchor of A, at a higher fee/fee-rate than B. Next, Mallory broadcasts B3, double-spending B2 by spending Mallory's input but not the ephemeral anchor of A. Assuming Mallory needed to mine B3 anyway, the only cost to this attack is the small chance that B2 will in fact be mined between the time that B2 is replaced by B3.
At this point A is no longer economical to mine as B has been cycled out, and A may be dropped from mempools depending on the circumstances.
## SIGHASH_ANYONECANPAY
Obviously, a similar attack is possible against SIGHASH_ANYONECANPAY-using transactions, provided that _all_ signatures sign with SIGHASH_ANYONECANPAY.
# Countermeasures
As with other replacement cycling attacks, rebroadcasting A and B fixes the issue. I think the existence of this additional type of replacement cycling attack suggests that adding an optional rebroadcasting module to Bitcoin Core that would keep track of dropped transactions and re-add them to mempools when they are again valid would make sense. This fixes all replacement cycling attacks and there's probably lots of nodes who have the memory and/or disk space to keep track of dropped transactions like this.
Preventing the replacement of B2 with B3 is _not_ a viable countermeasure: if that replacement was prohibited, attackers could in turn exploit that rule as a new form of transaction pinning!
# Privacy
The fact that rebroadcasting is a countermeasure is a privacy concern. Each time a transaction is rebroadcast by the sender is a potential opportunity to track the origin of a transaction. Again, having third parties rebroadcasting transactions altruistically would mitigate this privacy concern.
Quoted text (1 line)
> I think the existence of this additional type of replacement cycling
attack suggests that adding an optional rebroadcasting module to Bitcoin Core that would keep track of dropped transactions and re-add them to mempools when they are again valid would make sense. This fixes all replacement cycling attacks and there's probably lots of nodes who have the memory and/or disk space to keep track of dropped transactions like this.
It kinda seems like this might introduce a DOS vector to the nodes running this module since you can keep cycling B3, B4 etc. and force the mempool to house all of these until one of them gets mined. Further, it would cause the mempool to have to decide which of these dead transactions gets priority upon the eviction of the conflicting one. Is this something you've given thought to? Admittedly I haven't dived deep into it.
Keags
On Fri, Aug 2, 2024 at 5:30 AM Peter Todd <pete@petertodd•org> wrote:
Quoted text (88 lines)
> This feels like someone should have published it before. But I can't find > an > obvious citation (eg in any of the documentation around keyless ephemeral > anchors), so I'll publish one here. Maybe I'm the first to point this out > explicitly? Probably not; I'd appreciate an earlier citation if one exists. > > > tl;dr: _Anyone_ can do a replacement cycling attack on transactions where > fees > are paid via CPFP via keyless anchors and similar outputs that a > third-party > can double-spend. Secondly, for attackers who were already planning on > making a > transaction with a higher total fee and total fee-rate than the target, > this > attack is almost free. > > > # The Attack > > Suppose that Alice has created a 2 transaction package consisting of > low-fee or > zero-fee transaction A, whose fees are CPFP paid via a keyless ephemeral > anchor > spent by transaction B. For B to pay fees, obviously it must spend a second > transaction output. > > Mallory can cycle A and B out of mempools by broadcasting transaction B2, > spending his own output and the keyless ephemeral anchor of A, at a higher > fee/fee-rate than B. Next, Mallory broadcasts B3, double-spending B2 by > spending Mallory's input but not the ephemeral anchor of A. Assuming > Mallory > needed to mine B3 anyway, the only cost to this attack is the small chance > that > B2 will in fact be mined between the time that B2 is replaced by B3. > > At this point A is no longer economical to mine as B has been cycled out, > and A > may be dropped from mempools depending on the circumstances. > > > ## SIGHASH_ANYONECANPAY > > Obviously, a similar attack is possible against SIGHASH_ANYONECANPAY-using > transactions, provided that _all_ signatures sign with > SIGHASH_ANYONECANPAY. > > > # Countermeasures > > As with other replacement cycling attacks, rebroadcasting A and B fixes the > issue. I think the existence of this additional type of replacement cycling > attack suggests that adding an optional rebroadcasting module to Bitcoin > Core > that would keep track of dropped transactions and re-add them to mempools > when > they are again valid would make sense. This fixes all replacement cycling > attacks and there's probably lots of nodes who have the memory and/or disk > space to keep track of dropped transactions like this. > > Preventing the replacement of B2 with B3 is _not_ a viable countermeasure: > if > that replacement was prohibited, attackers could in turn exploit that rule > as a > new form of transaction pinning! > > > # Privacy > > The fact that rebroadcasting is a countermeasure is a privacy concern. Each > time a transaction is rebroadcast by the sender is a potential opportunity > to > track the origin of a transaction. Again, having third parties > rebroadcasting > transactions altruistically would mitigate this privacy concern. > > -- > https://petertodd.org 'peter'[:-1]@petertodd.org > > -- > You received this message because you are subscribed to the Google Groups > "Bitcoin Development Mailing List" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to bitcoindev+unsubscribe@googlegroups•com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/bitcoindev/ZqyQtNEOZVgTRw2N%40petertodd.org > . >
Hello,
Quoted text (1 line)
> This feels like someone should have published it before. But I can't find
an
Quoted text (3 lines)
> obvious citation (eg in any of the documentation around keyless ephemeral > anchors), so I'll publish one here. Maybe I'm the first to point this out > explicitly? Probably not; I'd appreciate an earlier citation if one
exists.
Same, I cannot remember about an earlier citation in doucmentation around keyless ephemeral anchors, and while this is a concern I was aware of I was expecting that some reviewer of ephemeral anchors would figure it out earlier (or at least praying for that...).
Quoted text (1 line)
> tl;dr: _Anyone_ can do a replacement cycling attack on transactions where
fees
Quoted text (1 line)
> are paid via CPFP via keyless anchors and similar outputs that a
third-party
Quoted text (1 line)
> can double-spend. Secondly, for attackers who were already planning on
making a
Quoted text (1 line)
> transaction with a higher total fee and total fee-rate than the target,
this
Quoted text (1 line)
> attack is almost free.
Yes, about the second observation, see the section 5.2 about high-fee collaboration transactions advantage in the write-up which was initially released at the disclosure of replacement cycling attacks [0].
[0] https://github.com/ariard/mempool-research/blob/2023-10-replacement-paper/replacement-cycling.pdf
In my belief, the simple fact that any bitcoin economical actor originating transaction traffic at regular interval (e.g LSP or exchange batching) can leverage that position to engage in replacement cycling attacks is a real worry.
Quoted text (3 lines)
> # The Attack > > Suppose that Alice has created a 2 transaction package consisting of
low-fee or
Quoted text (1 line)
> zero-fee transaction A, whose fees are CPFP paid via a keyless ephemeral
anchor
Quoted text (1 line)
> spent by transaction B. For B to pay fees, obviously it must spend a
second
Quoted text (6 lines)
> transaction output. > > Mallory can cycle A and B out of mempools by broadcasting transaction B2, > spending his own output and the keyless ephemeral anchor of A, at a higher > fee/fee-rate than B. Next, Mallory broadcasts B3, double-spending B2 by > spending Mallory's input but not the ephemeral anchor of A. Assuming
Mallory
Quoted text (1 line)
> needed to mine B3 anyway, the only cost to this attack is the small
chance that
Quoted text (3 lines)
> B2 will in fact be mined between the time that B2 is replaced by B3. > > At this point A is no longer economical to mine as B has been cycled out,
and A
Quoted text (1 line)
> may be dropped from mempools depending on the circumstances.
Yes, in my understanding this scenario works. I think can even maliciously batch B3 to replace a N number of keyless spending B2 transactions at the same time.
Quoted text (4 lines)
> ## SIGHASH_ANYONECANPAY > > Obviously, a similar attack is possible against SIGHASH_ANYONECANPAY-using > transactions, provided that _all_ signatures sign with
SIGHASH_ANYONECANPAY.
Yes, a single SIGHASH_ALL locks-in the spent input, and as such avoid a third-party to adds a higher-fee / feerate input, then to be ulteriorly conflited with. There might be some data carriage style transactions using this pattern...
Quoted text (3 lines)
> # Countermeasures > > As with other replacement cycling attacks, rebroadcasting A and B fixes
the
Quoted text (1 line)
> issue. I think the existence of this additional type of replacement
cycling
Quoted text (1 line)
> attack suggests that adding an optional rebroadcasting module to Bitcoin
Core
Quoted text (1 line)
> that would keep track of dropped transactions and re-add them to mempools
when
Quoted text (5 lines)
> they are again valid would make sense. This fixes all replacement cycling > attacks and there's probably lots of nodes who have the memory and/or disk > space to keep track of dropped transactions like this. > > Preventing the replacement of B2 with B3 is _not_ a viable
countermeasure: if
Quoted text (1 line)
> that replacement was prohibited, attackers could in turn exploit that
rule as a
Quoted text (1 line)
> new form of transaction pinning!
I still think altruistic rebroadcasting is a very limited mitigation as even beefy nodes have computationally-limited memory and/or disk spaces. They would need to have some ordering of the dropped transactions e.g caches by tiers of feerate group and a replacement cycling attacker would just have to spam the top cache.
I believe it was already discussed there and in the previous email (I might be missing something ?) [1].
[1] https://groups.google.com/g/bitcoindev/c/qEx4K8lGnLk/m/AMPqDi6MBwAJ
Quoted text (3 lines)
> # Privacy > > The fact that rebroadcasting is a countermeasure is a privacy concern.
Each
Quoted text (1 line)
> time a transaction is rebroadcast by the sender is a potential
opportunity to
Quoted text (1 line)
> track the origin of a transaction. Again, having third parties
rebroadcasting
Quoted text (1 line)
> transactions altruistically would mitigate this privacy concern.
Yes...On the other hand third parties rebroadcasting transactions are now exposing themselves to be injected DoS traffic. Having full-nodes offering a threshold of their memory / CPU cyles to process anonymizing traffic is great, especially for the marginal lighnting user. When it's a lightning hub with a lot of channel funds, I believe it's naive to expect those additional memory / CPU cyles cannot be spammed for exploitation purposes.
Quoted text (1 line)
> It kinda seems like this might introduce a DOS vector to the nodes
running this
Quoted text (1 line)
> module since you can keep cycling B3, B4 etc. and force the mempool to
house
Quoted text (1 line)
> all of these until one of them gets mined. Further, it would cause the
mempool
Quoted text (1 line)
> to have to decide which of these dead transactions gets priority upon the
eviction
Quoted text (1 line)
> of the conflicting one. Is this something you've given thought to?
Admittedly I
Quoted text (1 line)
> haven't dived deep into it.
I did, and effectively you're running into hierarchy of caches management styles of issues [2]
[2] https://github.com/bitcoin/bitcoin/issues/28699
Best, Antoine ots hash: eba1b16753146707a07dcd1aee1ca066fcb323e18222be7282088c49d9f44266 Le vendredi 2 août 2024 à 23:00:16 UTC+1, Keagan McClelland a écrit :
Quoted text (119 lines)
> > I think the existence of this additional type of replacement cycling > attack suggests that adding an optional rebroadcasting module to Bitcoin > Core > that would keep track of dropped transactions and re-add them to mempools > when > they are again valid would make sense. This fixes all replacement cycling > attacks and there's probably lots of nodes who have the memory and/or disk > space to keep track of dropped transactions like this. > > It kinda seems like this might introduce a DOS vector to the nodes running > this > module since you can keep cycling B3, B4 etc. and force the mempool to > house > all of these until one of them gets mined. Further, it would cause the > mempool > to have to decide which of these dead transactions gets priority upon the > eviction > of the conflicting one. Is this something you've given thought to? > Admittedly I > haven't dived deep into it. > > Keags > > On Fri, Aug 2, 2024 at 5:30 AM Peter Todd <pe...@petertodd•org> wrote: > >> This feels like someone should have published it before. But I can't find >> an >> obvious citation (eg in any of the documentation around keyless ephemeral >> anchors), so I'll publish one here. Maybe I'm the first to point this out >> explicitly? Probably not; I'd appreciate an earlier citation if one >> exists. >> >> >> tl;dr: _Anyone_ can do a replacement cycling attack on transactions where >> fees >> are paid via CPFP via keyless anchors and similar outputs that a >> third-party >> can double-spend. Secondly, for attackers who were already planning on >> making a >> transaction with a higher total fee and total fee-rate than the target, >> this >> attack is almost free. >> >> >> # The Attack >> >> Suppose that Alice has created a 2 transaction package consisting of >> low-fee or >> zero-fee transaction A, whose fees are CPFP paid via a keyless ephemeral >> anchor >> spent by transaction B. For B to pay fees, obviously it must spend a >> second >> transaction output. >> >> Mallory can cycle A and B out of mempools by broadcasting transaction B2, >> spending his own output and the keyless ephemeral anchor of A, at a higher >> fee/fee-rate than B. Next, Mallory broadcasts B3, double-spending B2 by >> spending Mallory's input but not the ephemeral anchor of A. Assuming >> Mallory >> needed to mine B3 anyway, the only cost to this attack is the small >> chance that >> B2 will in fact be mined between the time that B2 is replaced by B3. >> >> At this point A is no longer economical to mine as B has been cycled out, >> and A >> may be dropped from mempools depending on the circumstances. >> >> >> ## SIGHASH_ANYONECANPAY >> >> Obviously, a similar attack is possible against SIGHASH_ANYONECANPAY-using >> transactions, provided that _all_ signatures sign with >> SIGHASH_ANYONECANPAY. >> >> >> # Countermeasures >> >> As with other replacement cycling attacks, rebroadcasting A and B fixes >> the >> issue. I think the existence of this additional type of replacement >> cycling >> attack suggests that adding an optional rebroadcasting module to Bitcoin >> Core >> that would keep track of dropped transactions and re-add them to mempools >> when >> they are again valid would make sense. This fixes all replacement cycling >> attacks and there's probably lots of nodes who have the memory and/or disk >> space to keep track of dropped transactions like this. >> >> Preventing the replacement of B2 with B3 is _not_ a viable >> countermeasure: if >> that replacement was prohibited, attackers could in turn exploit that >> rule as a >> new form of transaction pinning! >> >> >> # Privacy >> >> The fact that rebroadcasting is a countermeasure is a privacy concern. >> Each >> time a transaction is rebroadcast by the sender is a potential >> opportunity to >> track the origin of a transaction. Again, having third parties >> rebroadcasting >> transactions altruistically would mitigate this privacy concern. >> >> -- >> https://petertodd.org 'peter'[:-1]@petertodd.org >> >> -- >> You received this message because you are subscribed to the Google Groups >> "Bitcoin Development Mailing List" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to bitcoindev+...@googlegroups•com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/bitcoindev/ZqyQtNEOZVgTRw2N%40petertodd.org >> . >> >