Welcome to Microsoft Q&A!
Thank you for the additional clarification and for explaining the design in more detail.
Based on your description, I understand that your design does not rely on ClientPID as a process-object reference and does not perform a subsequent OpenProcess(ClientPID) lookup. Instead, a trusted launcher retains the original process handle returned by CreateProcess, and ClientPID is used only as evidence of call origin by comparing it with GetProcessId(H).
From the publicly available Microsoft documentation, ClientPID is described in call-specific terms:
- RPC_CALL_ATTRIBUTES_V2_A (rpcasync.h) states that ClientPID contains the process ID of the calling client and is populated when RPC_QUERY_CLIENT_PID is specified. It is supported only for the ncalrpc protocol sequence.
- I_RpcBindingInqLocalClientPID function (rpcdcep.h) states that it returns the process ID of the client that issued the call.
- The same API may return RPC_S_NO_CALL_ACTIVE when there is no active RPC call on the current thread.
- RpcServerInqCallAttributesA function (rpcasync.h) obtains client security context attributes and is used in the context of a server routine or a specific asynchronous RPC call.
Taken together, this documentation supports the interpretation that, for an active ncalrpc call, ClientPID refers to the process ID of the immediate RPC client that issued that call.
That said, it is important to recognize the limits of what is explicitly documented. The available documentation does not describe:
- When the PID is captured internally by the RPC runtime.
- Whether the runtime retains any underlying process-object reference.
- How attribution behaves in scenarios involving proxying, forwarding, or other implementation-specific mechanisms.
- Whether Microsoft defines a comparison such as ClientPID == GetProcessId(H) as a supported security boundary.
For that reason, while the documented wording ("calling client" and "client that issued the call") is consistent with your interpretation, the published documentation does not provide a formal guarantee beyond that statement.
Therefore, based on the currently available Microsoft documentation, the most supportable conclusion is:
For an active ncalrpc call, ClientPID is documented as the process ID of the immediate client process that issued that RPC call.
However, the documentation does not elevate ClientPID itself into a non-reassignable process reference, nor does it explicitly define broader security-boundary guarantees around that value. In the design you described, the retained process handle H remains the component that provides process-occurrence continuity.
Regarding escalation, Microsoft Q&A contributors are limited to information that is publicly documented and do not have a direct mechanism to obtain official confirmation from the Windows RPC product team. If your scenario requires a formal product-backed statement regarding the contractual semantics of ClientPID, the appropriate path would be to engage Microsoft Support, where the question may be reviewed through the relevant engineering channels.
I hope this helps clarify both what can reasonably be concluded from the published documentation and where the current documentation leaves room for interpretation.
References:
I_RpcBindingInqLocalClientPID function (rpcdcep.h) - Win32 apps | Microsoft Learn
RPC_CALL_ATTRIBUTES_V2_A (rpcasync.h) - Win32 apps | Microsoft Learn
RpcServerInqCallAttributesA function (rpcasync.h) - Win32 apps | Microsoft Learn
Client Impersonation (RPC) - Win32 apps | Microsoft Learn
I_RpcBindingInqLocalPID | Microsoft Learn
Rpcdcep.h header - Win32 apps | Microsoft Learn
Remote Procedure Call (RPC) - Win32 apps | Microsoft Learn
The Client Application - Win32 apps | Microsoft Learn
If you find it useful, please click Accept Answer.
Thank you for choosing Microsoft Q&A.