Audit report AR-23

Reported privately in an independent security review, 2026-08-16.

Report date
2026-08-16
Kind
Hardening
Status on master
Present
Proposed issue state
Open
Linked bugs
Bug 55: Node memory grows while Stratum v2 mining clients are connected

Summary

A mining client can keep requesting block templates over IPC and hold on to every one of them, because bitcoin-node has no limit on the number of live BlockTemplate objects. The report is accurate and presents a limit as resource hardening; it demonstrated no memory threshold or failure. A limit would bound how much memory a client can pin, which may be relevant to the open report of unbounded memory growth with Stratum v2 clients, although no link between the two has been shown.

The report

Each successful template result (from createNewBlock or waitNext) creates another server object that the client holds independently, and the node has no process-wide budget for them. The socket is opt-in and already grants local clients unauthenticated RPC access, so the report calls this a resource-management proposal, not a new authority boundary. A client needs access to the configured socket and must keep requesting and retaining template handles; releasing the handles or closing the connection frees them. No retained-memory threshold, visible service failure, or deployment with a less privileged client was demonstrated.

Its test, a 107-line addition to src/ipc/test/ipc_tests.cpp run through the real IPC listeners, checks the proposed accounting with lightweight test templates. The report notes that this says nothing about the memory cost of real mining templates.

Proposed change

A new -ipcblocktemplatecapabilities=<n> option (default 16) limits the number of live block-template capabilities in the node. A slot is reserved when a block-template server is created and released when its implementation is destroyed; when no slot is free, the request fails:

+template <>
+struct ProxyServerImpl<interfaces::BlockTemplate>
+{
+    template <typename Value>
+    static std::shared_ptr<interfaces::BlockTemplate> Make(Value&& value)
+    {
+        if (!ipc::capnp::ReserveBlockTemplateCapability()) {
+            throw std::runtime_error("IPC block template capability limit reached");
+        }
+        auto release_slot = [](interfaces::BlockTemplate* block_template) {
+            delete block_template;
+            ipc::capnp::ReleaseBlockTemplateCapability();
+        };

The report says the default of 16 changes admission policy (excess requests get an error until a template is released), and that the libmultiprocess hook is an upstream API proposal.

Assessment

Accurate: on Bitcoin Core master nothing limits live ProxyServer<BlockTemplate> objects. Real templates hold a full block and fee data, so a client that leaks template handles, for example by never calling destroy and never dropping them, grows node memory until it disconnects. That makes a limit a plausible mitigation for the open, unexplained memory growth in bitcoin-node memory grows without bound while Stratum v2 clients use the IPC mining interface, but not an explanation: the report does not claim a link, and none has been shown.

Under Bitcoin Core's trust model a client that can reach the socket already has unauthenticated RPC access, so this is hardening, not a stability bug. As written the patch is speculative: a fixed default of 16 could reject pools that legitimately keep several templates per connection or serve many downstream clients, a process-wide limit lets one client starve another, and the subtree hook needs agreement in libmultiprocess.

Related resource-limit reports: AR-04 (threads), AR-07 (per-method quotas), AR-09 and AR-19 (connections), AR-22 (unresolved calls).

Status

Present on master. Next step: understand the memory growth in bitcoin#33940 first; if retained templates turn out to matter, discuss a per-connection limit and the libmultiprocess hook. Idea; no issue open.

Reported privately in an independent security review on 2026-08-16.