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:
-ipcbindis documented as giving local processes that can access the socket unauthenticated RPC access, so socket permissions are the authentication boundary.- After that boundary, the username is a deliberate selector: the review of bitcoin#32297, which added RPC over IPC, considered ignoring IPC usernames for whitelist checks and chose instead that IPC and HTTP callers with the same username see the same method policy.
- The report's own functional test did not compare like with like: its IPC call used an empty username while its HTTP request authenticated as
__cookie__, so the test showed the proposed policy, not a defect.
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.