<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://brunoerg.xyz/feed.xml" rel="self" type="application/atom+xml" /><link href="http://brunoerg.xyz/" rel="alternate" type="text/html" /><updated>2026-03-10T17:50:08+00:00</updated><id>http://brunoerg.xyz/feed.xml</id><title type="html">Bruno Garcia</title><subtitle>Posts</subtitle><author><name>Bruno Garcia</name></author><entry><title type="html">2 DoS vulnerabilities on Floresta</title><link href="http://brunoerg.xyz/2026/03/10/dos-floresta.html" rel="alternate" type="text/html" title="2 DoS vulnerabilities on Floresta" /><published>2026-03-10T00:00:00+00:00</published><updated>2026-03-10T00:00:00+00:00</updated><id>http://brunoerg.xyz/2026/03/10/dos-floresta</id><content type="html" xml:base="http://brunoerg.xyz/2026/03/10/dos-floresta.html"><![CDATA[<p>I just discovered and reported 2 DoS vulnerabilities that affect the Floresta software. 
The first one is regarding a large memory allocation that is done when allocating the header from a V1 message. I noticed that when the V2 (BIP324) handshake fails, it falls back to the V1. 
However, when deserializing the header, there was no size check, so a “huge” header would cause the data to be resized in a way that could cause it to run out of memory. See:</p>

<pre><code class="language-rs">let header: V1MessageHeader = deserialize_partial(&amp;data)?.0;
data.resize(24 + header.length as usize, 0);
reader.read_exact(&amp;mut data[24..]).await?;
</code></pre>

<p>The other vulnerability is regarding the rate-limiting mechanism implemented in Floresta. It checks if a peer is sending more than 10 messages per second; if so, the peer is disconnected. However, the counter (<code>messages</code>) was never incremented, so it was always zero, and the mechanism had no effect.</p>

<pre><code class="language-rs">// divide the number of messages by the number of seconds we've been connected,
// if it's more than 10 msg/sec, this peer is sending us too many messages, and we should
// disconnect.
let msg_sec = self
    .messages
    .checked_div(Instant::now().duration_since(self.start_time).as_secs())
    .unwrap_or(0);

if msg_sec &gt; 10 {
    error!(
        "Peer {} is sending us too many messages, disconnecting",
        self.id
    );
    return Err(PeerError::TooManyMessages);    
</code></pre>

<hr />

<p>Both vulnerabilities are fixed in https://github.com/getfloresta/Floresta/pull/880.</p>]]></content><author><name>Bruno Garcia</name></author><category term="Other" /><summary type="html"><![CDATA[I just discovered and reported 2 DoS vulnerabilities that affect the Floresta software. The first one is regarding a large memory allocation that is done when allocating the header from a V1 message. I noticed that when the V2 (BIP324) handshake fails, it falls back to the V1. However, when deserializing the header, there was no size check, so a “huge” header would cause the data to be resized in a way that could cause it to run out of memory. See:]]></summary></entry><entry><title type="html">Gocoin incorrectly parsing OP_PUSHDATA4</title><link href="http://brunoerg.xyz/2026/02/19/gocoin-consensus-bug.html" rel="alternate" type="text/html" title="Gocoin incorrectly parsing OP_PUSHDATA4" /><published>2026-02-19T00:00:00+00:00</published><updated>2026-02-19T00:00:00+00:00</updated><id>http://brunoerg.xyz/2026/02/19/gocoin-consensus-bug</id><content type="html" xml:base="http://brunoerg.xyz/2026/02/19/gocoin-consensus-bug.html"><![CDATA[<p>Gocoin is a full Bitcoin solution written entirely from scratch in Go language with zero dependencies, according to their website. We are differentially fuzzing its <code>VerifyTxScript</code> function against Bitcoin Core’s <code>VerifyScript</code>. These functions are consensus critical and they are responsible for verifying <code>scriptPubKey</code> and <code>scriptSig</code>.</p>

<p>During the execution, we got a crash with the following scripts:</p>

<pre><code class="language-sh">scriptSig: 5b00
scriptPubKey: 00004c020f600100009f9a000102020202004e000064a2a2a2a2a2000000a2a2a2a2a2a2a2a2 
</code></pre>

<p>The error returned by Bitcoin Core is <code>SCRIPT_ERR_BAD_OPCODE</code> that was being returned due to <code>OP_PUSHDATA4</code> claiming more bytes than are available.</p>

<p><code>GetOp()</code> attempts to advance pc by 100 bytes, overshoots the end of the script buffer, and then, returns false. Looking at <code>gocoin</code>’s code, the similar function to Core’s <code>GetOpcode</code> is <code>GetOp</code>:</p>

<pre><code class="language-go">func GetOpcode(b []byte) (opcode int, ret []byte, pc int, e error) {
	// Read instruction
	if pc+1 &gt; len(b) {
		e = errors.New("GetOpcode error 1")
		return
	}
	opcode = int(b[pc])
	pc++

	if opcode &lt;= OP_PUSHDATA4 {
		size := 0
		if opcode &lt; OP_PUSHDATA1 {
			size = opcode
		}
		if opcode == OP_PUSHDATA1 {
			if pc+1 &gt; len(b) {
				e = errors.New("GetOpcode error 2")
				return
			}
			size = int(b[pc])
			pc++
		} else if opcode == OP_PUSHDATA2 {
			if pc+2 &gt; len(b) {
				e = errors.New("GetOpcode error 3")
				return
			}
			size = int(binary.LittleEndian.Uint16(b[pc : pc+2]))
			pc += 2
		} else if opcode == OP_PUSHDATA4 {
			if pc+4 &gt; len(b) {
				e = errors.New("GetOpcode error 4")
				return
			}
			size = int(binary.LittleEndian.Uint16(b[pc : pc+4]))
			pc += 4
		}
		if pc+size &gt; len(b) {
			e = errors.New(fmt.Sprint("GetOpcode size to fetch exceeds remainig data left: ", pc+size, "/", len(b)))
			return
		}
		ret = b[pc : pc+size]
		pc += size
	}

	return
}
</code></pre>

<p>The issue is that gocoin was using <code>Uint16</code> in the context of <code>OP_PUSHDATA4</code> instead of using <code>Uint32</code>. The size field is explicitly defined as a 4-byte little-endian unsigned integer.</p>

<hr />

<p>Thanks Piotr Narewski for responding to my report and fixing the bug so quickly. Also, he told me to go ahead and disclosure it.</p>]]></content><author><name>Bruno Garcia</name></author><category term="Other" /><summary type="html"><![CDATA[Gocoin is a full Bitcoin solution written entirely from scratch in Go language with zero dependencies, according to their website. We are differentially fuzzing its VerifyTxScript function against Bitcoin Core’s VerifyScript. These functions are consensus critical and they are responsible for verifying scriptPubKey and scriptSig.]]></summary></entry><entry><title type="html">Gocoin incorrectly parsing OP_0NOTEQUAL</title><link href="http://brunoerg.xyz/2026/01/22/gocoin-consensus-bug.html" rel="alternate" type="text/html" title="Gocoin incorrectly parsing OP_0NOTEQUAL" /><published>2026-01-22T00:00:00+00:00</published><updated>2026-01-22T00:00:00+00:00</updated><id>http://brunoerg.xyz/2026/01/22/gocoin-consensus-bug</id><content type="html" xml:base="http://brunoerg.xyz/2026/01/22/gocoin-consensus-bug.html"><![CDATA[<p>Gocoin is a full Bitcoin solution written entirely from scratch in Go language with zero dependencies, according to their website. Since it is a full node implementation, we thought it would be good to have it on <code>bitcoinfuzz</code>, especially for the target that evaluates Bitcoin scripts.</p>

<p><a href="https://github.com/abhiramjampani">Abhiramjampani</a> worked on it and opened a PR recently. It is missing addressing some key concerns, brought by Erick, which is why the PR has not been merged yet. However, as part of the review, we left this target running for some time, and it quickly crashed with the following script, which gocoin returned success and Bitcoin Core false:</p>

<p><code>-1 OP_HASH256 OP_0NOTEQUAL</code></p>

<p>I first checked that the target was properly implemented and then jumped to understand where the bug was happening. Conceptually, I understand that this is script is not valid, because the hash generated by the opcode <code>OP_HASH256</code> does not fit in the 4 bytes required by the arithmetic opcodes (<code>OP_0NOTEQUAL</code>, in this case). The gocoin’s code - at that moment - to parse this opcode was:</p>

<pre><code class="language-go">d := stack.pop()
if checkMinVals &amp;&amp; len(d) &gt; 1 {
  if DBG_ERR {
    fmt.Println("Not minimal bool value", hex.EncodeToString(d))
  }
  return false
}
</code></pre>

<p>As can be seen, it was using <code>pop</code> to get the element instead of using <code>popInt</code>, which makes it not fail for values longer than 4 bytes. The fix was addressed <a href="https://github.com/piotrnar/gocoin/commit/42763e1efb5f09ab563aa95a288b1dbe92b90cce">here</a> by Piotr and can be seen in the following diff:</p>

<pre><code class="language-diff">-				d := stack.pop()
-				if checkMinVals &amp;&amp; len(d) &gt; 1 {
-					if DBG_ERR {
-						fmt.Println("Not minimal bool value", hex.EncodeToString(d))
-					}
-					return false
-				}
-				stack.pushBool(bts2bool(d))
+				stack.pushBool(stack.popInt(checkMinVals) != 0)
</code></pre>

<hr />

<p>Thanks Piotr Narewski for responding to my report and fixing the bug so quickly. Also, he told me to go ahead and disclosure it.</p>]]></content><author><name>Bruno Garcia</name></author><category term="Other" /><summary type="html"><![CDATA[Gocoin is a full Bitcoin solution written entirely from scratch in Go language with zero dependencies, according to their website. Since it is a full node implementation, we thought it would be good to have it on bitcoinfuzz, especially for the target that evaluates Bitcoin scripts.]]></summary></entry><entry><title type="html">Security Concerns Regarding Floresta’s Address Relay and AddrMan Implementation</title><link href="http://brunoerg.xyz/2026/01/16/floresta-security-addr.html" rel="alternate" type="text/html" title="Security Concerns Regarding Floresta’s Address Relay and AddrMan Implementation" /><published>2026-01-16T00:00:00+00:00</published><updated>2026-01-16T00:00:00+00:00</updated><id>http://brunoerg.xyz/2026/01/16/floresta-security-addr</id><content type="html" xml:base="http://brunoerg.xyz/2026/01/16/floresta-security-addr.html"><![CDATA[<p>Recently, I reported to @Davidson-Souza some security concerns about Floresta’s address relay and addrman (address manager), especially some non-conformities with BIP155. Since Floresta is running only in Signet, he told me to share these thoughts for learning purposes. As soon as Floresta gets ready for “production” use, they will adopt a responsible disclosure policy.</p>

<h2 id="violation-of-the-1000-address-limit-in-addrv2">Violation of the 1,000-Address Limit in addrv2</h2>

<p>First of all, I noticed that Floresta, when sending addresses to other peers, was not respecting the rule of sending at most 1’000 addresses per message. This number is specified in BIP 155, where the addrv2 message is defined. The BIP says:</p>

<pre><code class="language-sh">One message can contain up to 1,000 addresses. Client SHOULD reject messages with more addresses.
</code></pre>

<p>Violating this limit could cause Floresta nodes to be disconnected and even banned from other full-node implementations such as Bitcoin Core. Also, at the same time, Floresta was not respecting this number when sending addresses, and it was also not verifying it when receiving addresses, resulting in the acceptance of a large number of addresses per message.</p>

<h2 id="storing-addresses-from-unsupported-or-unreachable-networks">Storing Addresses from Unsupported or Unreachable Networks</h2>

<p>Another issue identified in Floresta’s handling of incoming addrv2 messages is the storage and propagation of addresses belonging to networks that Floresta neither supports nor can reach. As a result, Floresta may store and relay addresses that it has no ability to validate.</p>

<p>This behavior directly contradicts the guidance provided in BIP155, which states:</p>

<pre><code>Clients SHOULD NOT gossip addresses from unknown networks because they have no means to validate those addresses and so can be tricked to gossip invalid addresses.
</code></pre>

<p>Relaying such addresses increases the risk of polluting the address gossip network with invalid or malicious entries.</p>

<h2 id="acceptance-of-private-addresses">Acceptance of Private Addresses</h2>

<p>Finally, Floresta relies on Rust’s standard library to determine whether an IP address is private. However, the standard library does not classify the 0.255.255.255 address range as private. As a consequence, Floresta currently accepts and processes addresses within this range, despite them being non-routable and invalid for peer-to-peer communication.</p>

<hr />

<ul>
  <li>These concerns allowed me to be able to crash a (limited-resource) florestad by spamming large addrv2 messages. Also, I could fill and bloat the address manager.</li>
  <li>Davidson is promptly addressing these concerns <a href="https://github.com/getfloresta/Floresta/pull/781">floresta@781</a></li>
  <li>I also suggested them to adopt a rate-limit for this message, like Bitcoin Core.</li>
</ul>]]></content><author><name>Bruno Garcia</name></author><category term="Other" /><summary type="html"><![CDATA[Recently, I reported to @Davidson-Souza some security concerns about Floresta’s address relay and addrman (address manager), especially some non-conformities with BIP155. Since Floresta is running only in Signet, he told me to share these thoughts for learning purposes. As soon as Floresta gets ready for “production” use, they will adopt a responsible disclosure policy.]]></summary></entry><entry><title type="html">Nbitcoin Consensus Bug</title><link href="http://brunoerg.xyz/2025/11/24/nbitcoin-consensus-bug.html" rel="alternate" type="text/html" title="Nbitcoin Consensus Bug" /><published>2025-11-24T00:00:00+00:00</published><updated>2025-11-24T00:00:00+00:00</updated><id>http://brunoerg.xyz/2025/11/24/nbitcoin-consensus-bug</id><content type="html" xml:base="http://brunoerg.xyz/2025/11/24/nbitcoin-consensus-bug.html"><![CDATA[<p>We recently integrated NBitcoin into the script_eval target of bitcoinfuzz.This target performs differential fuzzing of Bitcoin script evaluation logic by comparing the behavior of EvalScript (or equivalent) implementations across different projects.Before adding NBitcoin, this target was already fuzzing Bitcoin Core and btcd.</p>

<p>Shortly after starting the fuzzing campaign — thanks to an already good corpus — we encountered a crash with the following script:</p>

<pre><code>Hex: 000360670000005b770100000000005b770100000000000008777760779f00000877776077
Asm: 0 26464 0 0 11 OP_NIP 0 0 0 0 0 11 OP_NIP 0 0 0 0 0 0 777760779f000008 OP_NIP OP_NIP 16 OP_NIP
</code></pre>

<p>When debugging the run output, we observed that NBitcoin returned false while Bitcoin Core returned true. Since this represented a clear consensus discrepancy, we manually reviewed the script to verify whether it was valid. The analysis confirmed that the script is valid, meaning that Bitcoin Core’s behavior is correct — and that the discrepancy originated from a bug in NBitcoin.</p>

<p>Initially, this was surprising, since the only opcode in the script is OP_NIP, which removes the second item from the top of the stack — a relatively simple operation. NBitcoin’s implementation of this opcode is shown below:</p>

<pre><code class="language-csharp">case OpcodeType.OP_NIP:
{
    // (x1 x2 -- x2)
    if (_stack.Count &lt; 2)
        return SetError(ScriptError.InvalidStackOperation);

    _stack.Remove(-2);
    break;
}
</code></pre>

<p>To better understand the issue, we created a test case and stepped through <code>EvalScript</code>. During execution, an IndexOutOfRangeException was thrown when processing the third OP_NIP.</p>

<p>Further investigation revealed the following:</p>

<blockquote>
  <p>When the underlying array is at full capacity (e.g., 16 elements), and <code>_stack.Remove(-2)</code> is called, the Remove operation must delete the item at index 14 and shift the subsequent elements down. During this shift, the implementation may attempt to access _array[16], which does not exist, leading to the IndexOutOfRangeException.</p>
</blockquote>

<p>Interestingly, this bug was only discovered through differential fuzzing, because the discrepancy in return values between <code>Bitcoin Core</code> and <code>NBitcoin</code> highlighted the problem. Since the exception occurs within a try/catch block (preventing a full crash), fuzzing by itself might not catch it.</p>

<p>Timeline:</p>

<p>2025-10-23 - Bruno Garcia reports the issue to Nicolas Dorier</p>

<p>2025-10-23 - Nicolas Dorier confirmed the issue</p>

<p>2025-10-23 - Nicolas Dorier opens #1288 to fix it</p>

<p>2025-10-23 - NBitcoin 9.0.3 is released</p>

<p><em>Note: There is no known node implementation using NBitcoin, so there is no risk of chain split. That’s why we’re making it public.</em></p>]]></content><author><name>Bruno Garcia</name></author><category term="Other" /><summary type="html"><![CDATA[We recently integrated NBitcoin into the script_eval target of bitcoinfuzz.This target performs differential fuzzing of Bitcoin script evaluation logic by comparing the behavior of EvalScript (or equivalent) implementations across different projects.Before adding NBitcoin, this target was already fuzzing Bitcoin Core and btcd.]]></summary></entry><entry><title type="html">The state of Bitcoinfuzz</title><link href="http://brunoerg.xyz/2025/08/21/the-state-of-bitcoinfuzz.html" rel="alternate" type="text/html" title="The state of Bitcoinfuzz" /><published>2025-08-21T00:00:00+00:00</published><updated>2025-08-21T00:00:00+00:00</updated><id>http://brunoerg.xyz/2025/08/21/the-state-of-bitcoinfuzz</id><content type="html" xml:base="http://brunoerg.xyz/2025/08/21/the-state-of-bitcoinfuzz.html"><![CDATA[<p><strong>bitcoinfuzz</strong> is a project that does differential fuzzing of Bitcoin protocol implementations and libraries. I originally created it as an experiment, and the first version was quite rough with a poor design.
As the project started gaining attention, I refactored it to follow a modular approach similar to cryptofuzz. It means that you can choose which projects you want to fuzz, and you can build the projects (we call modules) individually.</p>

<p>The first targets that I wrote were descriptor and miniscript parsers, where we found many bugs. The first one we reported was in sipa’s miniscript implementation, which incorrectly considered <code>pk()()</code> as a valid policy because it identifies <code>)(</code> as the name. Currently, we have many other targets like: script evaluation, descriptor parse, miniscript parse, addrv2, psbt, address parse, and others. We plan to expand and work on additional targets in the near future.</p>

<p>So far, we discovered and reported over 35 bugs in projects such as btcd, rust-bitcoin, rust-miniscript, Embit, Bitcoin Core, Core Lightning, LND, etc. Examples include: many implementations using the incorrect type for the key’s type value for PSBTs, the CVE-2024-44073 of rust-miniscript, panic on btcd’s PSBT parser (https://github.com/btcsuite/btcd/issues/2351), Embit incorrectly pointing a miniscript as valid (https://github.com/bitcoinfuzz/bitcoinfuzz/issues/113), Core Lightning accepting invoices with non-standard witness address fallbacks that other implementations correctly reject (https://github.com/ElementsProject/lightning/pull/8219).</p>

<h2 id="what-are-the-current-projects-we-support">What are the current projects we support?</h2>

<p>We currently integrate and support the following projects:</p>

<ul>
  <li>Bitcoin Core - C++</li>
  <li>rust-bitcoin - Rust</li>
  <li>rust-miniscript - Rust</li>
  <li>embit - Python</li>
  <li>btcd - Golang</li>
  <li>LDK - Rust</li>
  <li>LND - Golang</li>
  <li>Core Lightning - C</li>
  <li>NLightning - C#</li>
  <li>NBitcoin - C#</li>
  <li>Eclair - Scala</li>
  <li>lightning-kmp - Kotlin</li>
</ul>

<p>There is a PR (under review) that integrates libbitcoin. We welcome any PR that integrates more projects into bitcoinfuzz. However, we intend to review the support of some implementations since an immature implementation can hinder differential fuzzing with simple issues. For example, Embit’s miniscript/descriptor implementation is still incomplete, with many fragments not supported. We also experimented with Mako support, but decided to remove it because the project is not currently being maintained.</p>

<h2 id="lightning-network-on-bitcoinfuzz">Lightning Network on Bitcoinfuzz</h2>

<p>Differential fuzzing of Lightning implementations is proving to be highly valuable.. To advance this effort Erick Cestari and Morehouse have joined the project. Erick began working on it as a Vinteum fellow, mentored by Bruno and Morehouse, and more recently received a full grant from Vinteum. So far, bitcoinfuzz includes targets for BOLT11 invoice decoding and BOLT12 offer decoding. There are also open pull requests adding lightning-kmp module for invoice deserialization, BOLT12 invoice request decoding, adding Eclair module for invoice deserialization, and more.</p>

<p>One advantage of applying differential fuzzing to Lightning implementations is that the Lightning Network has a well maintained specification. It means that when we find any discrepancy, we can reference the spec to determine the correct behavior. This is not the case for Bitcoin protocol implementations, where we mostly rely on Bitcoin Core as the reference. However, we have seen that differential fuzzing is also a good tool to improve the Lightning spec itself. From our experience, the specification is not always clear and often leaves room for improvement. As an example, one of the bitcoinfuzz trophies is a fix on the bolt12 specification, where a currency UTF-8 test vector lacked the required 3-byte length. As a result, many implementations were treating it as a case of malformed currency length instead of properly validating the UTF-8 encoding.</p>

<p>Also, bitcoinfuzz found bugs in virtually every implementation we support. E.g.</p>

<ul>
  <li>Core Lightning was accepting invoices with non-standard witness address fallbacks that other implementations correctly reject;</li>
  <li>When deserializing an invoice with a large expiry value, LND produces a negative expiry value due to overflow;</li>
  <li>rust-lightning was not verifying whether the offer_currency field contains valid UTF-8 for invoices.</li>
  <li>Eclair was accepting bolt11 invoices with empty routing hints in the r field.</li>
</ul>

<h2 id="doing-differential-fuzzing-of-projects-that-do-not-have-fuzz-testing">Doing differential fuzzing of projects that do not have fuzz testing</h2>

<p>Some projects either lack support for fuzzing altogether or do not run their fuzz targets continuously. In these cases, we sometimes find bugs not because of the
“differential” aspect, but simply because the project has not been fuzzed at all. As an example, we found and reported a panic on btcd when parsing a PSBT due to a bug on the <code>ReadTaprootBip32Derivation</code> functions. This type of bug could have been easily caught by a basic fuzz target and a few minutes of execution. Similar cases occurred with rust-miniscript and lightning-kmp.</p>

<h2 id="nuances-can-also-get-in-the-way">Nuances can also get in the way</h2>

<p>When we find a discrepancy between two implementations, it doesn’t always mean there is a bug in one of them. Sometimes small differences in behavior lead to interesting cases. For example, Bitcoin Core accepted miniscripts and descriptors with integer values containing trailing zeros or a positive sign (+) - e.g. <code>older(+1)</code> or <code>older(000001)</code>, we believe that no one uses it in practice, however, since rust-miniscript rejects these cases, it would cause a discrepancy between them. That said, Bitcoin Core addressed it in https://github.com/bitcoin/bitcoin/pull/30577 by using ToIntegral instead of ParseInt64.</p>

<h2 id="oss-fuzz">OSS-Fuzz</h2>

<p>We recently opened a PR to integrate bitcoinfuzz into OSS-Fuzz, Google’s continuous fuzzing infrastructure for open‑source software. We believe that it would benefit our project a lot since we currently have a limited fuzzing infrastructure.</p>

<h2 id="corpora">Corpora</h2>

<p>We created a repository where we share some corpora for our fuzzing targets, similar to Bitcoin Core’s qa-assets. However, we might keep two folders per target. One folder with all the inputs (maximizing coverage) and another excluding inputs that we know would trigger crashes - e.g. when we’re waiting for an implementation to fix a reported bug. The goal of the second folder is to make it possible to run bitcoinfuzz in CI/CD pipelines.</p>

<h2 id="future-work">Future work</h2>

<p>We have several directions we’re eager to explore. In the short term, our focus is on expanding bitcoinfuzz to be fully agnostic and compatible with multiple fuzzing engines beyond libFuzzer. We also plan to introduce new fuzzing targets—such as BOLT8, BOLT7, BOLT4 and ElligatorSwift/V2 Transport — and to strengthen our build system, with a particular emphasis on resolving linking issues.</p>]]></content><author><name>Bruno Garcia</name></author><category term="Other" /><summary type="html"><![CDATA[bitcoinfuzz is a project that does differential fuzzing of Bitcoin protocol implementations and libraries. I originally created it as an experiment, and the first version was quite rough with a poor design. As the project started gaining attention, I refactored it to follow a modular approach similar to cryptofuzz. It means that you can choose which projects you want to fuzz, and you can build the projects (we call modules) individually.]]></summary></entry><entry><title type="html">rust-miniscript vulnerability disclosure (DoS/Stack Overflow) - CVE-2024-44073</title><link href="http://brunoerg.xyz/2024/08/12/rust-miniscript-vuln.html" rel="alternate" type="text/html" title="rust-miniscript vulnerability disclosure (DoS/Stack Overflow) - CVE-2024-44073" /><published>2024-08-12T00:00:00+00:00</published><updated>2024-08-12T00:00:00+00:00</updated><id>http://brunoerg.xyz/2024/08/12/rust-miniscript-vuln</id><content type="html" xml:base="http://brunoerg.xyz/2024/08/12/rust-miniscript-vuln.html"><![CDATA[<p>On 2nd July, we (Kartik Agarwala (<a href="https://github.com/hax0kartik">hax0kartik</a>) and I) reported a stack overflow issue on rust-miniscript to Andrew Poelstra. We discovered that rust-miniscript could stack overflow when parsing a miniscript from a string due to a recursion. From our conversations, the reason was that the constant <code>MAX_RECURSION_DEPTH</code> was not being applied to prefix combinators like <code>n:</code>. It means the parser would take these “large” miniscripts and (iteratively) construct a tree with a very high depth. Then, this will stack overflow when doing any recursive operation. All the miniscript websites that help visualize/parse miniscript using <code>rust-miniscript</code> could crash with this input.</p>

<p>Affects: <code>rust-miniscript</code> 9, 10, 11 and 12.</p>

<hr />

<h3 id="how-did-we-find-it">How did we find it?</h3>

<p><strong>TL;DR: Fuzzing</strong></p>

<p><a href="https://github.com/brunoerg/bitcoinfuzz">Bitcoinfuzz</a> is a project that applies differential fuzzing in Bitcoin implementations and libraries. One of the targets does differential fuzzing with <code>rust-miniscript</code> and <code>Bitcoin Core</code> for parsing a miniscript from a string. So far, it found some bugs and has been helpful.</p>

<p>However, <code>bitcoinfuzz</code> had only support for <code>libfuzzer</code> and, at some point, Kartik suggested using some structures from <code>Bitcoin Core</code> to add support for more fuzzers in <code>bitcoinfuzz</code>. So, we started using <code>bitcoinfuzz</code> with AFL and, even fuzzing for a long time with libfuzzer, this bug was found in a few minutes with AFL. Just luck? We don’t know haha.</p>

<h4 id="why-the-issue-was-not-discovered-before">Why the issue was not discovered before?</h4>

<p>Both <code>rust-bitcoin</code> and <code>rust-miniscript</code> support fuzzing. Also, <code>rust-miniscript</code> has two targets called <code>roundtrip_miniscript_str</code> and <code>roundtrip_miniscript_script</code> which should be able to find this. However, the effectiveness of fuzzing depends on large campaigns, that is why it is important that both projects are continually fuzzed.</p>

<h3 id="timeline">Timeline</h3>

<p><strong>07/02/2024</strong> - Reported the issue to Andrew Poelstra via e-mail. <br />
<strong>07/02/2024</strong> - Andrew confirmed the issue and cc’ed Sanket. <br />
<strong>07/08/2024</strong> - Sanket reproduced the issue and opened a PR addressing it. <br />
<strong>07/08/2024</strong> - I tested and confirmed the fix. <br />
<strong>07/18/2024</strong> - Andrew discovered that the issue could also affect parsing Miniscripts from Script. <br />
<strong>07/18/2024</strong> - Sanket started working on a fix for it. <br />
<strong>07/20/2024</strong> - Sanket opened a PR addressing it. <br />
<strong>08/06/2024</strong> - I verified that all fixes were backported. Andrew and Sanket confirmed this, and we proceeded to have a CVE.</p>

<h3 id="responsible-disclosure">Responsible Disclosure</h3>

<p>We have found <strong>MANY</strong> bugs with bitcoinfuzz, and we have carefully analyzed all of them to know what is just a simple bug and what could be something more critical. Critical bugs/vulnerabilities have been reported to the according project team.</p>

<h3 id="acknowledgements">Acknowledgements</h3>

<p>I would like to first thank Kartik Agarwala for working with me on this project. Kartik is a Summer of Bitcoin intern and he has done a brillant work. Also, thanks Andrew and Sanket for the cooperation on it and other cases.</p>]]></content><author><name>Bruno Garcia</name></author><category term="Other" /><summary type="html"><![CDATA[On 2nd July, we (Kartik Agarwala (hax0kartik) and I) reported a stack overflow issue on rust-miniscript to Andrew Poelstra. We discovered that rust-miniscript could stack overflow when parsing a miniscript from a string due to a recursion. From our conversations, the reason was that the constant MAX_RECURSION_DEPTH was not being applied to prefix combinators like n:. It means the parser would take these “large” miniscripts and (iteratively) construct a tree with a very high depth. Then, this will stack overflow when doing any recursive operation. All the miniscript websites that help visualize/parse miniscript using rust-miniscript could crash with this input.]]></summary></entry></feed>