Audit report AR-65

Reported privately in an independent security review, 2026-09-27.

Report date
2026-09-27
Kind
Hardening
Status on master
Present
Proposed issue state
Open

Summary

When Bitcoin Core reads a serialized value, such as a transaction id or a transaction, from an IPC Data field, it decodes one value and ignores any bytes left over. A 33-byte transaction id is read as its first 32 bytes, and a transaction with an extra byte appended is read as the original transaction. The report is accurate. The leftover bytes are simply dropped, so nothing breaks and no result changes, but rejecting malformed input is the right contract. A small validation fix for Bitcoin Core.

The report

Bitcoin Core's generic conversion for IPC Data fields decodes one C++ value without requiring the input to end there. A 33-byte txid or wtxid is accepted as its 32-byte prefix, and an immutable transaction with an appended byte can be accepted as the original transaction.

The report rates it as protocol hardening with routine urgency. It needs access to the optional local IPC interface and deliberately malformed input. No additional authority and no availability, funds or consensus effect was shown.

Proposed change

After decoding, require the input to be fully consumed, in both conversion routes (types decoded in place, and types built by a deserializing constructor). Truncated input keeps its existing error.

         value.Unserialize(wrapper);
+        if (!stream.empty()) throw std::runtime_error{"IPC Data contains trailing bytes"};
     });
 ...
-    return read_dest.construct(::deserialize, wrapper);
+    decltype(auto) result = read_dest.construct(::deserialize, wrapper);
+    if (!stream.empty()) throw std::runtime_error{"IPC Data contains trailing bytes"};
+    return result;

A unit test sends a transaction with one extra byte and expects the error, then checks a normal call on the same connection still works. The functional test interface_ipc_mining.py sends 31-byte and 33-byte transaction ids and witness ids to the two transaction lookup methods and expects the truncation and trailing-bytes errors. The report considered checking only the length of hashes, rejected because transactions and other serialized types would still accept suffixes.

Assessment

Accurate. On Bitcoin Core master, both generic readers in src/ipc/capnp/common-types.h decode from a byte reader over the field and return without checking that the reader is empty. Transaction ids take this path rather than libmultiprocess's own reader for raw byte types, which copies the whole field and so has no such issue.

There is no stability effect and no wrong result. A transaction id with extra bytes looks up its first 32 bytes, and a transaction or block with extra bytes is used, and hashed, in its decoded form, so the extra bytes are dropped. Only a client that sends malformed data sees any difference, and IPC clients are trusted. Rejecting trailing data still matches how Bitcoin Core's RPC decoders treat serialized input, and the fix is two lines in Bitcoin Core with no library change. It is worth taking. Naming the field type in the error message would help whoever has to debug a rejected call.

Status

Present on master. Hardening; no public issue or PR yet.

Reported privately in an independent security review on 2026-09-27.