Audit report AR-20

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

Report date
2026-08-16
Kind
Docs
Status on master
Not applicable
Proposed issue state
Open

Summary

RPC calls made over IPC carry a username chosen by the client, and Bitcoin Core applies that user's -rpcwhitelist settings to the call. The report first proposed treating this as an authorization bypass and ignoring the IPC username; in its final form it concludes that the behaviour is intended and recommends documenting it instead. The survey agrees: not a bug. What remains is a documentation point, that the IPC username selects per-user behaviour and is not an authenticated identity.

The report

interfaces::Rpc::executeRpc() lets an IPC client run a JSON-RPC request, passing a user string that RpcImpl stores in JSONRPCRequest::authUser before calling the shared HTTP RPC dispatcher. That dispatcher applies -rpcwhitelist and -rpcwhitelistdefault for the named user. The original concern was that an IPC client can pick any username and so pick any user's whitelist, or an empty one.

The report in its final form explains why this premise does not hold:

It also notes that RPC over IPC and bitcoin-cli -ipcconnect are not in any release up to 31.1. It finds no authorization bypass, privilege increase or remote route.

Proposed change

The original patch made every IPC request skip per-user whitelist checks, by adding a transport field to JSONRPCRequest and discarding the username in RpcImpl:

-        bool user_has_whitelist = g_rpc_whitelist.contains(jreq.authUser);
-        if (!user_has_whitelist && g_rpc_whitelist_default) {
+        const bool apply_user_whitelist{jreq.transport == JSONRPCRequest::Transport::HTTP};
+        const bool user_has_whitelist{apply_user_whitelist && g_rpc_whitelist.contains(jreq.authUser)};
+        if (apply_user_whitelist && !user_has_whitelist && g_rpc_whitelist_default) {
@@ class RpcImpl : public Rpc
-        req.authUser = std::move(user);
+        req.transport = JSONRPCRequest::Transport::IPC;
+        (void)user;

with matching comments in rpc.capnp, interfaces/rpc.h and the -rpcwhitelist help. The report's final recommendation is not to merge it: keep the user field, its assignment to authUser and the whitelist behaviour, and replace the patch's comments with documentation that the value is a trusted selector, not an authenticated principal. It suggests testing empty-username behaviour for bitcoin-cli separately, and that any test compare the same username and method over both transports.

Assessment

The behaviour on Bitcoin Core master is intended (req.authUser = std::move(user); in RpcImpl::executeRpc). ryanofsky, replying to the report, wrote that "IPC connections are trusted", and that usernames are accepted not for authentication but "to allow method behavior to vary by user, maybe offering different functionality or different wallets"; ignoring them removes that without a benefit. The report was withdrawn with the same reasoning.

The documentation suggestion has merit. The comment on executeRpc in rpc.capnp and the -ipcbind help could say that the username selects per-user behaviour and is not checked. No stability effect; outside the survey's scope.

Status

Not applicable: the behaviour is by design and the patch should not be merged. A doc-only change to the Rpc.executeRpc comment and the -ipcbind help text would capture the useful part. Idea; no issue open.

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