Audit report AR-52

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

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

Summary

Starting with v32, bitcoin-cli tries the node's IPC socket before HTTP by default (-ipcconnect=auto). If the socket belongs to an older v30 or v31 bitcoin-node, which accepts the connection but does not implement the RPC-over-IPC method added in v32, the command fails instead of falling back to HTTP. The report is accurate and its fix is small and safe. It is a compatibility problem in a new feature, not a stability bug: one command fails with an error, the node is unaffected, and -noipcconnect works around it.

The report

-ipcconnect=auto is meant to use HTTP whenever the node's IPC socket cannot serve RPC. Today it only falls back when connecting to the socket fails. A v30 or v31 node started with -ipcbind=unix accepts the connection, but it has no Init.makeRpc method, so the newer CLI gets an "unimplemented method" error and stops. The report says a real v31.1 node made the default CLI call fail while -noipcconnect returned the requested block count, and that v32.0rc2 has the same code.

The report rates it low and asks for a decision before v32.0. It needs a v32 bitcoin-cli, an older local node with -ipcbind=unix, and ordinary access to that node's data directory and RPC credentials. Only that one command is affected.

Proposed change

Remember whether the caller asked for auto before the connection code replaces that value with the address it used, and fall back to HTTP if creating the RPC interface fails in auto mode. An explicit -ipcconnect=unix still reports the IPC error.

+    // connectAddress() replaces "auto" with the address it used.
+    const bool auto_connect{ipcconnect == "auto"};
     ...
-    std::unique_ptr<interfaces::Rpc> rpc{node_init->makeRpc()};
+    std::unique_ptr<interfaces::Rpc> rpc;
+    try {
+        rpc = node_init->makeRpc();
+    } catch (const std::exception&) {
+        // No RPC request has been sent, so auto mode can still use HTTP.
+        if (auto_connect) return {};
+        throw;
+    }

The functional test interface_ipc_cli.py starts a small Python Cap'n Proto server that answers like a pre-v32 node and checks that the default mode reaches HTTP while -ipcconnect=unix reports the IPC error. The report considered matching only the "unimplemented" error text (fragile) and adding version negotiation to the protocol (too broad for a compatibility fix).

Assessment

Accurate. In src/bitcoin-cli.cpp, CallIPC() only wraps the connection attempt in try, and calls makeRpc() after it with no handling. connectAddress() in src/ipc/interfaces.cpp rewrites "auto" to "unix" before it connects, so the CLI cannot tell afterwards that it was in auto mode. Both makeRpc and the auto default came in bitcoin#32297, merged for v32, so no released node implements the method. The v31.1 run was not repeated here.

The fallback is safe. Unlike a failed connection, it happens after the CLI has already talked to the node, but makeRpc() fails before any RPC request is built or sent, so nothing can run twice, and falling back on any error from makeRpc() rather than only "unimplemented" is fine for the same reason. The exposure is small: older nodes only open the socket with -ipcbind=unix, which mostly mining setups use. Since the fix needs the same "was this auto mode?" flag as AR-53, the two fit in one Bitcoin Core PR.

Not counted as a stability bug in this survey: no crash, hang or leak.

Status

Present on master and in v32.0rc2. Next step: a Bitcoin Core PR, together with AR-53. No public issue or PR yet.

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