Audit report AR-55
Reported privately in an independent security review, 2026-09-27.
- Report date
- 2026-09-27
- Kind
- Design
- Status on master
- Present
- Proposed issue state
- Open
Summary
An RPC reply larger than about 64 MiB fails when bitcoin-cli uses IPC, while the same call works over HTTP. The cause is Cap'n Proto's default per-message limit, which libmultiprocess uses for every connection, combined with the RPC-over-IPC method returning the whole JSON reply in one message. Since v32 makes bitcoin-cli try IPC first, this is a change in what the CLI can do. The report is accurate. It is not a stability bug: the call fails with an error and the connection and node keep working. It is the concrete case for letting applications set this limit (AR-07).
The report
bitcoin-cli now tries local IPC before HTTP. Every libmultiprocess connection uses Cap'n Proto's default traversal limit of 8 Mi words in both directions, which also caps a whole message at about 64 MiB. Rpc.executeRpc returns the complete JSON reply as a single text field, so a valid larger reply is rejected over IPC even though HTTP returns it.
The report's example is decoderawtransaction for a transaction with 215,000 outputs: with the proposed change it returned the same 105,024,382 bytes over IPC and HTTP. Without the change the IPC call failed while HTTP succeeded; that run was not repeated on the final version, but a 65 MiB library test showed the same limit. The node stayed up, and -noipcconnect is a workaround. The report rates it low and asks for a decision before v32.0.
Proposed change
Raise the traversal limit to 1 GiB for both directions of every libmultiprocess connection:
+inline ::capnp::ReaderOptions ConnectionReaderOptions()
+{
+ ::capnp::ReaderOptions options;
+ options.traversalLimitInWords = (uint64_t{1} << 30) / sizeof(::capnp::word);
+ return options;
+}
...
- m_network(*m_stream, ::capnp::rpc::twoparty::Side::CLIENT, ::capnp::ReaderOptions()),
+ m_network(*m_stream, ::capnp::rpc::twoparty::Side::CLIENT, ConnectionReaderOptions()),
A libmultiprocess test sends 65 MiB through a method and back and checks that the connection still works afterwards. The report rejected retrying over HTTP after a failed IPC reply, which could run a state-changing command twice, and noted that streaming results would keep a small limit but needs a schema change. It points out that a 1 GiB limit lets a trusted local peer make the other side parse and allocate much more per message, and that this was not measured.
Assessment
Accurate. Connection creates its Cap'n Proto network with default ReaderOptions on both sides, and rpc.capnp returns the reply as one Text value. The failure is clean: Cap'n Proto refuses to send a message larger than its own limit ("Trying to send Cap'n Proto message larger than our single-message size limit"), and the RPC layer turns that into an error reply, so the client gets an exception and can keep using the connection. Replies this large are rare in practice, for example decoding a very large transaction.
Because Cap'n Proto checks the limit when sending as well as when receiving, it is a property of the connection at both ends: raising it only where messages are read would not help, and an older node or client with the default limit still fails for large messages. The report's change sets one value inside the library for every application. A better shape is the one proposed for AR-07: let applications pass ReaderOptions per connection, with a larger library default, and have Bitcoin Core pick its own value. The higher memory allowance is acceptable under the current trust model, where a client that can reach the IPC socket already has full RPC access.
Not counted as a stability bug in this survey: the call fails with an error, without a crash, hang or leak.
Status
Present on master and in v32.0rc2. Next step: a libmultiprocess change that makes the limit configurable per connection with a larger default, followed by a subtree update in Bitcoin Core. No public issue or PR yet.
Reported privately in an independent security review on 2026-09-27.