/ doc / fuzzing.md
fuzzing.md
  1  # Fuzzing Bitcoin Core using libFuzzer
  2  
  3  ## Quickstart guide
  4  
  5  To quickly get started fuzzing Bitcoin Core using [libFuzzer](https://llvm.org/docs/LibFuzzer.html):
  6  
  7  ```sh
  8  $ git clone https://github.com/bitcoin/bitcoin
  9  $ cd bitcoin/
 10  $ ./autogen.sh
 11  $ CC=clang CXX=clang++ ./configure --enable-fuzz --with-sanitizers=address,fuzzer,undefined
 12  # macOS users: If you have problem with this step then make sure to read "macOS hints for
 13  # libFuzzer" on https://github.com/bitcoin/bitcoin/blob/master/doc/fuzzing.md#macos-hints-for-libfuzzer
 14  $ make
 15  $ FUZZ=process_message src/test/fuzz/fuzz
 16  # abort fuzzing using ctrl-c
 17  ```
 18  
 19  There is also a runner script to execute all fuzz targets. Refer to
 20  `./test/fuzz/test_runner.py --help` for more details.
 21  
 22  ## Overview of Bitcoin Core fuzzing
 23  
 24  [Google](https://github.com/google/fuzzing/) has a good overview of fuzzing in general, with contributions from key architects of some of the most-used fuzzers. [This paper](https://agroce.github.io/bitcoin_report.pdf) includes an external overview of the status of Bitcoin Core fuzzing, as of summer 2021.  [John Regehr](https://blog.regehr.org/archives/1687) provides good advice on writing code that assists fuzzers in finding bugs, which is useful for developers to keep in mind.
 25  
 26  ## Fuzzing harnesses and output
 27  
 28  [`process_message`](https://github.com/bitcoin/bitcoin/blob/master/src/test/fuzz/process_message.cpp) is a fuzzing harness for the [`ProcessMessage(...)` function (`net_processing`)](https://github.com/bitcoin/bitcoin/blob/master/src/net_processing.cpp). The available fuzzing harnesses are found in [`src/test/fuzz/`](https://github.com/bitcoin/bitcoin/tree/master/src/test/fuzz).
 29  
 30  The fuzzer will output `NEW` every time it has created a test input that covers new areas of the code under test. For more information on how to interpret the fuzzer output, see the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html).
 31  
 32  If you specify a corpus directory then any new coverage increasing inputs will be saved there:
 33  
 34  ```sh
 35  $ mkdir -p process_message-seeded-from-thin-air/
 36  $ FUZZ=process_message src/test/fuzz/fuzz process_message-seeded-from-thin-air/
 37  INFO: Seed: 840522292
 38  INFO: Loaded 1 modules   (424174 inline 8-bit counters): 424174 [0x55e121ef9ab8, 0x55e121f613a6),
 39  INFO: Loaded 1 PC tables (424174 PCs): 424174 [0x55e121f613a8,0x55e1225da288),
 40  INFO:        0 files found in process_message-seeded-from-thin-air/
 41  INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
 42  INFO: A corpus is not provided, starting from an empty corpus
 43  #2      INITED cov: 94 ft: 95 corp: 1/1b exec/s: 0 rss: 150Mb
 44  #3      NEW    cov: 95 ft: 96 corp: 2/3b lim: 4 exec/s: 0 rss: 150Mb L: 2/2 MS: 1 InsertByte-
 45  #4      NEW    cov: 96 ft: 98 corp: 3/7b lim: 4 exec/s: 0 rss: 150Mb L: 4/4 MS: 1 CrossOver-
 46  #21     NEW    cov: 96 ft: 100 corp: 4/11b lim: 4 exec/s: 0 rss: 150Mb L: 4/4 MS: 2 ChangeBit-CrossOver-
 47  #324    NEW    cov: 101 ft: 105 corp: 5/12b lim: 6 exec/s: 0 rss: 150Mb L: 6/6 MS: 5 CrossOver-ChangeBit-CopyPart-ChangeBit-ChangeBinInt-
 48  #1239   REDUCE cov: 102 ft: 106 corp: 6/24b lim: 14 exec/s: 0 rss: 150Mb L: 13/13 MS: 5 ChangeBit-CrossOver-EraseBytes-ChangeBit-InsertRepeatedBytes-
 49  #1272   REDUCE cov: 102 ft: 106 corp: 6/23b lim: 14 exec/s: 0 rss: 150Mb L: 12/12 MS: 3 ChangeBinInt-ChangeBit-EraseBytes-
 50          NEW_FUNC[1/677]: 0x55e11f456690 in std::_Function_base::~_Function_base() /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/std_function.h:255
 51          NEW_FUNC[2/677]: 0x55e11f465800 in CDataStream::CDataStream(std::vector<unsigned char, std::allocator<unsigned char> > const&, int, int) src/./streams.h:248
 52  #2125   REDUCE cov: 4820 ft: 4867 corp: 7/29b lim: 21 exec/s: 0 rss: 155Mb L: 6/12 MS: 2 CopyPart-CMP- DE: "block"-
 53          NEW_FUNC[1/9]: 0x55e11f64d790 in std::_Rb_tree<uint256, std::pair<uint256 const, std::chrono::duration<long, std::ratio<1l, 1000000l> > >, std::_Select1st<std::pair<uint256 const, std::chrono::duration<long, std::ratio<1l, 1000000l> > > >, std::less<uint256>, std::allocator<std::pair<uint256 const, std::chrono::duration<long, std::ratio<1l, 1000000l> > > > >::~_Rb_tree() /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/stl_tree.h:972
 54          NEW_FUNC[2/9]: 0x55e11f64d870 in std::_Rb_tree<uint256, std::pair<uint256 const, std::chrono::duration<long, std::ratio<1l, 1000000l> > >, std::_Select1st<std::pair<uint256 const, std::chrono::duration<long, std::ratio<1l, 1000000l> > > >, std::less<uint256>, std::allocator<std::pair<uint256 const, std::chrono::duration<long, std::ratio<1l, 1000000l> > > > >::_M_erase(std::_Rb_tree_node<std::pair<uint256 const, std::chrono::duration<long, std::ratio<1l, 1000000l> > > >*) /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/stl_tree.h:1875
 55  #2228   NEW    cov: 4898 ft: 4971 corp: 8/35b lim: 21 exec/s: 0 rss: 156Mb L: 6/12 MS: 3 EraseBytes-CopyPart-PersAutoDict- DE: "block"-
 56          NEW_FUNC[1/5]: 0x55e11f46df70 in std::enable_if<__and_<std::allocator_traits<zero_after_free_allocator<char> >::__construct_helper<char, unsigned char const&>::type>::value, void>::type std::allocator_traits<zero_after_free_allocator<char> >::_S_construct<char, unsigned char const&>(zero_after_free_allocator<char>&, char*, unsigned char const&) /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/alloc_traits.h:243
 57          NEW_FUNC[2/5]: 0x55e11f477390 in std::vector<unsigned char, std::allocator<unsigned char> >::data() /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/stl_vector.h:1056
 58  #2456   NEW    cov: 4933 ft: 5042 corp: 9/55b lim: 21 exec/s: 0 rss: 160Mb L: 20/20 MS: 3 ChangeByte-InsertRepeatedBytes-PersAutoDict- DE: "block"-
 59  #2467   NEW    cov: 4933 ft: 5043 corp: 10/76b lim: 21 exec/s: 0 rss: 161Mb L: 21/21 MS: 1 InsertByte-
 60  #4215   NEW    cov: 4941 ft: 5129 corp: 17/205b lim: 29 exec/s: 4215 rss: 350Mb L: 29/29 MS: 5 InsertByte-ChangeBit-CopyPart-InsertRepeatedBytes-CrossOver-
 61  #4567   REDUCE cov: 4941 ft: 5129 corp: 17/204b lim: 29 exec/s: 4567 rss: 404Mb L: 24/29 MS: 2 ChangeByte-EraseBytes-
 62  #6642   NEW    cov: 4941 ft: 5138 corp: 18/244b lim: 43 exec/s: 2214 rss: 450Mb L: 43/43 MS: 3 CopyPart-CMP-CrossOver- DE: "verack"-
 63  # abort fuzzing using ctrl-c
 64  $ ls process_message-seeded-from-thin-air/
 65  349ac589fc66a09abc0b72bb4ae445a7a19e2cd8 4df479f1f421f2ea64b383cd4919a272604087a7
 66  a640312c98dcc55d6744730c33e41c5168c55f09 b135de16e4709558c0797c15f86046d31c5d86d7
 67  c000f7b41b05139de8b63f4cbf7d1ad4c6e2aa7f fc52cc00ec1eb1c08470e69f809ae4993fa70082
 68  $ cat --show-nonprinting process_message-seeded-from-thin-air/349ac589fc66a09abc0b72bb4ae445a7a19e2cd8
 69  block^@M-^?M-^?M-^?M-^?M-^?nM-^?M-^?
 70  ```
 71  
 72  In this case the fuzzer managed to create a `block` message which when passed to `ProcessMessage(...)` increased coverage.
 73  
 74  It is possible to specify `bitcoind` arguments to the `fuzz` executable.
 75  Depending on the test, they may be ignored or consumed and alter the behavior
 76  of the test. Just make sure to use double-dash to distinguish them from the
 77  fuzzer's own arguments:
 78  
 79  ```sh
 80  $ FUZZ=address_deserialize_v2 src/test/fuzz/fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5 --printtoconsole=1
 81  ```
 82  
 83  ## Fuzzing corpora
 84  
 85  The project's collection of seed corpora is found in the [`bitcoin-core/qa-assets`](https://github.com/bitcoin-core/qa-assets) repo.
 86  
 87  To fuzz `process_message` using the [`bitcoin-core/qa-assets`](https://github.com/bitcoin-core/qa-assets) seed corpus:
 88  
 89  ```sh
 90  $ git clone https://github.com/bitcoin-core/qa-assets
 91  $ FUZZ=process_message src/test/fuzz/fuzz qa-assets/fuzz_seed_corpus/process_message/
 92  INFO: Seed: 1346407872
 93  INFO: Loaded 1 modules   (424174 inline 8-bit counters): 424174 [0x55d8a9004ab8, 0x55d8a906c3a6),
 94  INFO: Loaded 1 PC tables (424174 PCs): 424174 [0x55d8a906c3a8,0x55d8a96e5288),
 95  INFO:      991 files found in qa-assets/fuzz_seed_corpus/process_message/
 96  INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
 97  INFO: seed corpus: files: 991 min: 1b max: 1858b total: 288291b rss: 150Mb
 98  #993    INITED cov: 7063 ft: 8236 corp: 25/3821b exec/s: 0 rss: 181Mb
 99100  ```
101  
102  ## Run without sanitizers for increased throughput
103  
104  Fuzzing on a harness compiled with `--with-sanitizers=address,fuzzer,undefined` is good for finding bugs. However, the very slow execution even under libFuzzer will limit the ability to find new coverage. A good approach is to perform occasional long runs without the additional bug-detectors (configure `--with-sanitizers=fuzzer`) and then merge new inputs into a corpus as described in the qa-assets repo (https://github.com/bitcoin-core/qa-assets/blob/main/.github/PULL_REQUEST_TEMPLATE.md).  Patience is useful; even with improved throughput, libFuzzer may need days and 10s of millions of executions to reach deep/hard targets.
105  
106  ## Reproduce a fuzzer crash reported by the CI
107  
108  - `cd` into the `qa-assets` directory and update it with `git pull qa-assets`
109  - locate the crash case described in the CI output, e.g. `Test unit written to
110    ./crash-1bc91feec9fc00b107d97dc225a9f2cdaa078eb6`
111  - make sure to compile with all sanitizers, if they are needed (fuzzing runs
112    more slowly with sanitizers enabled, but a crash should be reproducible very
113    quickly from a crash case)
114  - run the fuzzer with the case number appended to the seed corpus path:
115    `FUZZ=process_message src/test/fuzz/fuzz
116    qa-assets/fuzz_seed_corpus/process_message/1bc91feec9fc00b107d97dc225a9f2cdaa078eb6`
117  
118  ## Submit improved coverage
119  
120  If you find coverage increasing inputs when fuzzing you are highly encouraged to submit them for inclusion in the [`bitcoin-core/qa-assets`](https://github.com/bitcoin-core/qa-assets) repo.
121  
122  Every single pull request submitted against the Bitcoin Core repo is automatically tested against all inputs in the [`bitcoin-core/qa-assets`](https://github.com/bitcoin-core/qa-assets) repo. Contributing new coverage increasing inputs is an easy way to help make Bitcoin Core more robust.
123  
124  ## macOS hints for libFuzzer
125  
126  The default Clang/LLVM version supplied by Apple on macOS does not include
127  fuzzing libraries, so macOS users will need to install a full version, for
128  example using `brew install llvm`.
129  
130  You may also need to take care of giving the correct path for `clang` and
131  `clang++`, like `CC=/path/to/clang CXX=/path/to/clang++` if the non-systems
132  `clang` does not come first in your path.
133  
134  Full configure that was tested on macOS with `brew` installed `llvm`:
135  
136  ```sh
137  ./configure --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++
138  ```
139  
140  Read the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html) for more information. This [libFuzzer tutorial](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md) might also be of interest.
141  
142  # Fuzzing Bitcoin Core using afl++
143  
144  ## Quickstart guide
145  
146  To quickly get started fuzzing Bitcoin Core using [afl++](https://github.com/AFLplusplus/AFLplusplus):
147  
148  ```sh
149  $ git clone https://github.com/bitcoin/bitcoin
150  $ cd bitcoin/
151  $ git clone https://github.com/AFLplusplus/AFLplusplus
152  $ make -C AFLplusplus/ source-only
153  $ ./autogen.sh
154  # If afl-clang-lto is not available, see
155  # https://github.com/AFLplusplus/AFLplusplus#a-selecting-the-best-afl-compiler-for-instrumenting-the-target
156  $ CC=$(pwd)/AFLplusplus/afl-clang-lto CXX=$(pwd)/AFLplusplus/afl-clang-lto++ ./configure --enable-fuzz
157  $ make
158  # For macOS you may need to ignore x86 compilation checks when running "make". If so,
159  # try compiling using: AFL_NO_X86=1 make
160  $ mkdir -p inputs/ outputs/
161  $ echo A > inputs/thin-air-input
162  $ FUZZ=bech32 AFLplusplus/afl-fuzz -i inputs/ -o outputs/ -- src/test/fuzz/fuzz
163  # You may have to change a few kernel parameters to test optimally - afl-fuzz
164  # will print an error and suggestion if so.
165  ```
166  
167  Read the [afl++ documentation](https://github.com/AFLplusplus/AFLplusplus) for more information.
168  
169  # Fuzzing Bitcoin Core using Honggfuzz
170  
171  ## Quickstart guide
172  
173  To quickly get started fuzzing Bitcoin Core using [Honggfuzz](https://github.com/google/honggfuzz):
174  
175  ```sh
176  $ git clone https://github.com/bitcoin/bitcoin
177  $ cd bitcoin/
178  $ ./autogen.sh
179  $ git clone https://github.com/google/honggfuzz
180  $ cd honggfuzz/
181  $ make
182  $ cd ..
183  $ CC=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang CXX=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang++ ./configure --enable-fuzz --with-sanitizers=address,undefined
184  $ make
185  $ mkdir -p inputs/
186  $ FUZZ=process_message honggfuzz/honggfuzz -i inputs/ -- src/test/fuzz/fuzz
187  ```
188  
189  Read the [Honggfuzz documentation](https://github.com/google/honggfuzz/blob/master/docs/USAGE.md) for more information.
190  
191  ## Fuzzing the Bitcoin Core P2P layer using Honggfuzz NetDriver
192  
193  Honggfuzz NetDriver allows for very easy fuzzing of TCP servers such as Bitcoin
194  Core without having to write any custom fuzzing harness. The `bitcoind` server
195  process is largely fuzzed without modification.
196  
197  This makes the fuzzing highly realistic: a bug reachable by the fuzzer is likely
198  also remotely triggerable by an untrusted peer.
199  
200  To quickly get started fuzzing the P2P layer using Honggfuzz NetDriver:
201  
202  ```sh
203  $ mkdir bitcoin-honggfuzz-p2p/
204  $ cd bitcoin-honggfuzz-p2p/
205  $ git clone https://github.com/bitcoin/bitcoin
206  $ cd bitcoin/
207  $ ./autogen.sh
208  $ git clone https://github.com/google/honggfuzz
209  $ cd honggfuzz/
210  $ make
211  $ cd ..
212  $ CC=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang \
213        CXX=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang++ \
214        ./configure --disable-wallet --with-gui=no \
215                    --with-sanitizers=address,undefined
216  $ git apply << "EOF"
217  diff --git a/src/compat/compat.h b/src/compat/compat.h
218  index 8195bceaec..cce2b31ff0 100644
219  --- a/src/compat/compat.h
220  +++ b/src/compat/compat.h
221  @@ -90,8 +90,12 @@ typedef char* sockopt_arg_type;
222   // building with a binutils < 2.36 is subject to this ld bug.
223   #define MAIN_FUNCTION __declspec(dllexport) int main(int argc, char* argv[])
224   #else
225  +#ifdef HFND_FUZZING_ENTRY_FUNCTION_CXX
226  +#define MAIN_FUNCTION HFND_FUZZING_ENTRY_FUNCTION_CXX(int argc, char* argv[])
227  +#else
228   #define MAIN_FUNCTION int main(int argc, char* argv[])
229   #endif
230  +#endif
231  
232   // Note these both should work with the current usage of poll, but best to be safe
233   // WIN32 poll is broken https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/
234  diff --git a/src/net.cpp b/src/net.cpp
235  index 7601a6ea84..702d0f56ce 100644
236  --- a/src/net.cpp
237  +++ b/src/net.cpp
238  @@ -727,7 +727,7 @@ int V1TransportDeserializer::readHeader(Span<const uint8_t> msg_bytes)
239       }
240  
241       // Check start string, network magic
242  -    if (memcmp(hdr.pchMessageStart, m_chain_params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) {
243  +    if (false && memcmp(hdr.pchMessageStart, m_chain_params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) { // skip network magic checking
244           LogPrint(BCLog::NET, "Header error: Wrong MessageStart %s received, peer=%d\n", HexStr(hdr.pchMessageStart), m_node_id);
245           return -1;
246       }
247  @@ -788,7 +788,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
248       RandAddEvent(ReadLE32(hash.begin()));
249  
250       // Check checksum and header message type string
251  -    if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) {
252  +    if (false && memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) { // skip checksum checking
253           LogPrint(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n",
254                    SanitizeString(msg.m_type), msg.m_message_size,
255                    HexStr(Span{hash}.first(CMessageHeader::CHECKSUM_SIZE)),
256  EOF
257  $ make -C src/ bitcoind
258  $ mkdir -p inputs/
259  $ honggfuzz/honggfuzz --exit_upon_crash --quiet --timeout 4 -n 1 -Q \
260        -E HFND_TCP_PORT=18444 -f inputs/ -- \
261            src/bitcoind -regtest -discover=0 -dns=0 -dnsseed=0 -listenonion=0 \
262                         -nodebuglogfile -bind=127.0.0.1:18444 -logthreadnames \
263                         -debug
264  ```
265  
266  # Fuzzing Bitcoin Core using Eclipser (v1.x)
267  
268  ## Quickstart guide
269  
270  To quickly get started fuzzing Bitcoin Core using [Eclipser v1.x](https://github.com/SoftSec-KAIST/Eclipser/tree/v1.x):
271  
272  ```sh
273  $ git clone https://github.com/bitcoin/bitcoin
274  $ cd bitcoin/
275  $ sudo vim /etc/apt/sources.list # Uncomment the lines starting with 'deb-src'.
276  $ sudo apt-get update
277  $ sudo apt-get build-dep qemu
278  $ sudo apt-get install libtool libtool-bin wget automake autoconf bison gdb
279  ```
280  
281  At this point, you must install the .NET core.  The process differs, depending on your Linux distribution.
282  See [this link](https://learn.microsoft.com/en-us/dotnet/core/install/linux) for details.
283  On Ubuntu 20.04, the following should work:
284  
285  ```sh
286  $ wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb
287  $ sudo dpkg -i packages-microsoft-prod.deb
288  $ rm packages-microsoft-prod.deb
289  $ sudo apt-get update
290  $ sudo apt-get install -y dotnet-sdk-2.1
291  ```
292  
293  You will also want to make sure Python is installed as `python` for the Eclipser install to succeed.
294  
295  ```sh
296  $ git clone https://github.com/SoftSec-KAIST/Eclipser.git
297  $ cd Eclipser
298  $ git checkout v1.x
299  $ make
300  $ cd ..
301  $ ./autogen.sh
302  $ ./configure --enable-fuzz
303  $ make
304  $ mkdir -p outputs/
305  $ FUZZ=bech32 dotnet Eclipser/build/Eclipser.dll fuzz -p src/test/fuzz/fuzz -t 36000 -o outputs --src stdin
306  ```
307  
308  This will perform 10 hours of fuzzing.
309  
310  To make further use of the inputs generated by Eclipser, you
311  must first decode them:
312  
313  ```sh
314  $ dotnet Eclipser/build/Eclipser.dll decode -i outputs/testcase -o decoded_outputs
315  ```
316  This will place raw inputs in the directory `decoded_outputs/decoded_stdins`.  Crashes are in the `outputs/crashes` directory, and must
317  be decoded in the same way.
318  
319  Fuzzing with Eclipser will likely be much more effective if using an existing corpus:
320  
321  ```sh
322  $ git clone https://github.com/bitcoin-core/qa-assets
323  $ FUZZ=bech32 dotnet Eclipser/build/Eclipser.dll fuzz -p src/test/fuzz/fuzz -t 36000 -i qa-assets/fuzz_seed_corpus/bech32 outputs --src stdin
324  ```
325  
326  Note that fuzzing with Eclipser on certain targets (those that create 'full nodes', e.g. `process_message*`) will,
327  for now, slowly fill `/tmp/` with improperly cleaned-up files, which will cause spurious crashes.
328  See [this proposed patch](https://github.com/bitcoin/bitcoin/pull/22472) for more information.
329  
330  Read the [Eclipser documentation for v1.x](https://github.com/SoftSec-KAIST/Eclipser/tree/v1.x) for more details on using Eclipser.
331  
332  
333  # OSS-Fuzz
334  
335  Bitcoin Core participates in Google's [OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/bitcoin-core)
336  program, which includes a dashboard of [publicly disclosed vulnerabilities](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=bitcoin-core).
337  Generally, we try to disclose vulnerabilities as soon as possible after they
338  are fixed to give users the knowledge they need to be protected. However,
339  because Bitcoin is a live P2P network, and not just standalone local software,
340  we might not fully disclose every issue within Google's standard
341  [90-day disclosure window](https://google.github.io/oss-fuzz/getting-started/bug-disclosure-guidelines/)
342  if a partial or delayed disclosure is important to protect users or the
343  function of the network.
344  
345  OSS-Fuzz also produces [a fuzzing coverage report](https://oss-fuzz.com/coverage-report/job/libfuzzer_asan_bitcoin-core/latest).