CVE-2026-10942
Overview
Background
- Named pipe squatting
- on Windows, whoever creates a named pipe first owns that name, so a less-privileged local process that creates a pipe a privileged client expects to connect to can pose as the legitimate server.
- `NamedPlatformChannel::Options`
- the Mojo options struct used to create or connect to named pipes and sockets; this patch adds
verify_server_privilege(Windows only, defaultfalse) and user-declaredOptions()/~Options(), which turns the struct into a non-aggregate. That is why many call sites change from designated initializers to field-by-field assignment. - Integrity level
- the Windows mandatory-integrity label on a process token (Low/Medium/High/System);
VerifyServerPrivilegecompares the server’s and the client’s levels usingbase::win::AccessToken. - `OpenRemoteProcess`
- an IPCz driver helper in
invitation.ccthat finds the peer of a connected named pipe and opens it withPROCESS_DUP_HANDLEso Mojo can duplicate handles into it.
Root Cause Analysis
Clients of privileged Chrome services on Windows (the updater’s update_service_dialer_win.cc, which already set allow_impersonation = true, and enterprise_companion_client.cc) connected to a well-known named pipe through named_mojo_ipc_server::ConnectToServer and trusted whichever process answered, without checking that the server was at least as privileged as the client. The client-endpoint creation path in named_platform_channel_win.cc returned the opened pipe handle as soon as it was valid.
The fix adds VerifyServerPrivilege, which resolves the server PID with GetNamedPipeServerProcessId, opens it with PROCESS_QUERY_LIMITED_INFORMATION, and requires server_token->IntegrityLevel() >= client_token->IntegrityLevel(). When options.verify_server_privilege is set, any failure returns an empty PlatformChannelEndpoint() instead of the connected handle, and the updater and enterprise-companion Windows dialers now set this flag. Separately, OpenRemoteProcess no longer relies on a caller-supplied remote_is_server role: it queries both GetNamedPipeClientProcessId and GetNamedPipeServerProcessId, takes whichever PID is not the current process, and rejects 0 or self. The removed code already returned an invalid process when the queried PID equalled the current PID, so this hunk makes role detection robust rather than closing an unchecked self-handle path. The commit itself describes the fix as hardening against a local privilege escalation in the updater and enterprise companion, while the advisory labels it “Insufficient validation of untrusted input in UI”.
Attack Path
- Squat the pipe name
A local, lower-integrity process creates the named pipe that the updater or enterprise companion server would normally publish (named via
GetUpdateServiceServerName(scope)/GetUpdateServiceInternalServerName(scope)or the companion’sserver_name), for example while the real server is not running (inferred timing). - Privileged client connects
A higher-integrity updater or enterprise-companion client calls
ConnectToServer; before the patch the client-endpoint path returned the squatter’s pipe handle without checking who owns it. - Mojo trusts the endpoint
The client builds its Mojo invitation over the attacker-owned pipe. For the updater this connection also allows impersonation (
allow_impersonation = true), so the squatting server can impersonate the client (inferred from the option name; the impersonation level is not shown). - Privilege abuse The attacker serves forged responses to, or acts with the identity of, the privileged client, which the commit describes as local privilege escalation (inferred beyond what the diff demonstrates).
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/updater/ipc/update_service_dialer_posix.cc |
modified | |
ifchrome/updater/ipc/update_service_dialer_win.cc |
modified | |
ifmojo/core/ipcz_driver/invitation.cc |
modified | |
NamedPlatformChannelmojo/public/cpp/platform/named_platform_channel.cc |
modified | |
ifmojo/public/cpp/platform/named_platform_channel_win.cc |
modified |
Files Changed
chrome/enterprise_companion/enterprise_companion_client.ccchrome/updater/ipc/update_service_dialer_posix.ccchrome/updater/ipc/update_service_dialer_win.ccchromeos/ash/experiences/arc/session/arc_session_impl.cccomponents/named_mojo_ipc_server/named_mojo_ipc_server_client_util.cccomponents/named_mojo_ipc_server/named_mojo_server_endpoint_connector_linux.cccomponents/named_mojo_ipc_server/named_mojo_server_endpoint_connector_mac.ccmojo/core/ipcz_driver/invitation.ccmojo/public/cpp/platform/named_platform_channel.ccmojo/public/cpp/platform/named_platform_channel.hmojo/public/cpp/platform/named_platform_channel_win.cc
Audit Directions
- Opt-in server authentication
verify_server_privilegedefaults tofalse; list every WindowsNamedPlatformChannel/named_mojo_ipc_serverclient that runs at elevated or SYSTEM integrity (elevation service, other updater internal services, remoting host, native messaging hosts) and check whether it still connects without verifying the server. - Strength of the check
VerifyServerPrivilegecompares only integrity levels and resolves the server by PID, so check for same-integrity squatting by a different user, PID reuse betweenGetNamedPipeServerProcessIdandOpenProcess, and whether the pipe DACL orFILE_FLAG_FIRST_PIPE_INSTANCEon the server side would be a stronger guard. - Peer-identity assumptions in IPC bootstrapReview other code that assumes the peer’s role or identity (client vs. server PID,
remote_is_server-style flags, socket peer credentials on POSIX/macOS) before granting powerful access such asPROCESS_DUP_HANDLEor impersonation.
Patch
diff --git a/chrome/enterprise_companion/enterprise_companion_client.cc b/chrome/enterprise_companion/enterprise_companion_client.cc
index c572cf2..1a1ccd1 100644
--- a/chrome/enterprise_companion/enterprise_companion_client.cc
+++ b/chrome/enterprise_companion/enterprise_companion_client.cc
@@ -103,8 +103,16 @@
return;
}
+#if BUILDFLAG(IS_WIN)
+ mojo::NamedPlatformChannel::Options options;
+ options.server_name = server_name;
+ options.verify_server_privilege = true;
+ mojo::PlatformChannelEndpoint endpoint =
+ named_mojo_ipc_server::ConnectToServer(options);
+#else
mojo::PlatformChannelEndpoint endpoint =
named_mojo_ipc_server::ConnectToServer(server_name);
+#endif
if (endpoint.is_valid()) {
std::move(callback).Run(std::move(endpoint));
return;
@@ -132,7 +140,14 @@
FROM_HERE, {base::MayBlock()},
base::BindOnce(
[](const mojo::NamedPlatformChannel::ServerName& server_name) {
+#if BUILDFLAG(IS_WIN)
+ mojo::NamedPlatformChannel::Options options;
+ options.server_name = server_name;
+ options.verify_server_privilege = true;
+ return named_mojo_ipc_server::ConnectToServer(options);
+#else
return named_mojo_ipc_server::ConnectToServer(server_name);
+#endif
},
server_name)
.Then(base::BindPostTaskToCurrentDefault(
diff --git a/chrome/updater/ipc/update_service_dialer_posix.cc b/chrome/updater/ipc/update_service_dialer_posix.cc
index 9724c9f4..b5d2e56 100644
--- a/chrome/updater/ipc/update_service_dialer_posix.cc
+++ b/chrome/updater/ipc/update_service_dialer_posix.cc
@@ -45,10 +45,11 @@
return std::nullopt;
}
- return named_mojo_ipc_server::ConnectToServer(
- {.server_name = is_internal_service
- ? GetUpdateServiceInternalServerName(scope)
- : GetUpdateServiceServerName(scope)});
+ mojo::NamedPlatformChannel::Options options;
+ options.server_name = is_internal_service
+ ? GetUpdateServiceInternalServerName(scope)
+ : GetUpdateServiceServerName(scope);
+ return named_mojo_ipc_server::ConnectToServer(options);
}();
if (!endpoint) {
diff --git a/chrome/updater/ipc/update_service_dialer_win.cc b/chrome/updater/ipc/update_service_dialer_win.cc
index 87a924bb..5c5f06f 100644
--- a/chrome/updater/ipc/update_service_dialer_win.cc
+++ b/chrome/updater/ipc/update_service_dialer_win.cc
@@ -84,12 +84,13 @@
}
server = result;
- return named_mojo_ipc_server::ConnectToServer({
- .server_name = is_internal_service
- ? GetUpdateServiceInternalServerName(scope)
- : GetUpdateServiceServerName(scope),
- .allow_impersonation = true,
- });
+ mojo::NamedPlatformChannel::Options options;
+ options.server_name = is_internal_service
+ ? GetUpdateServiceInternalServerName(scope)
+ : GetUpdateServiceServerName(scope);
+ options.allow_impersonation = true;
+ options.verify_server_privilege = true;
+ return named_mojo_ipc_server::ConnectToServer(options);
}();
if (tries >= 1 && !endpoint) {
diff --git a/chromeos/ash/experiences/arc/session/arc_session_impl.cc b/chromeos/ash/experiences/arc/session/arc_session_impl.cc
index fdd52826..99658e4a 100644
--- a/chromeos/ash/experiences/arc/session/arc_session_impl.cc
+++ b/chromeos/ash/experiences/arc/session/arc_session_impl.cc
@@ -271,7 +271,9 @@
}
}
- auto endpoint = mojo::NamedPlatformChannel({socket_path.value()});
+ mojo::NamedPlatformChannel::Options options;
+ options.server_name = socket_path.value();
+ auto endpoint = mojo::NamedPlatformChannel(options);
// TODO(cmtm): use NamedPlatformChannel to bootstrap mojo connection after
// libchrome uprev in android.
base::ScopedFD socket_fd =
diff --git a/components/named_mojo_ipc_server/named_mojo_ipc_server_client_util.cc b/components/named_mojo_ipc_server/named_mojo_ipc_server_client_util.cc
index d3c3173..f4bcbf6 100644
--- a/components/named_mojo_ipc_server/named_mojo_ipc_server_client_util.cc
+++ b/components/named_mojo_ipc_server/named_mojo_ipc_server_client_util.cc
@@ -57,7 +57,9 @@
// static
mojo::PlatformChannelEndpoint ConnectToServer(
const mojo::NamedPlatformChannel::ServerName& server_name) {
- return ConnectToServer({.server_name = server_name});
+ mojo::NamedPlatformChannel::Options options;
+ options.server_name = server_name;
+ return ConnectToServer(options);
}
} // namespace named_mojo_ipc_server
diff --git a/components/named_mojo_ipc_server/named_mojo_server_endpoint_connector_linux.cc b/components/named_mojo_ipc_server/named_mojo_server_endpoint_connector_linux.cc
index 1cfa150..c5cf0b7 100644
--- a/components/named_mojo_ipc_server/named_mojo_server_endpoint_connector_linux.cc
+++ b/components/named_mojo_ipc_server/named_mojo_server_endpoint_connector_linux.cc
@@ -106,8 +106,10 @@
bool NamedMojoServerEndpointConnectorLinux::TryStart() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ mojo::NamedPlatformChannel::Options options;
+ options.server_name = options_.server_name;
mojo::PlatformChannelServerEndpoint server_endpoint =
- mojo::NamedPlatformChannel({options_.server_name}).TakeServerEndpoint();
+ mojo::NamedPlatformChannel(options).TakeServerEndpoint();
if (!server_endpoint.is_valid()) {
return false;
}
diff --git a/components/named_mojo_ipc_server/named_mojo_server_endpoint_connector_mac.cc b/components/named_mojo_ipc_server/named_mojo_server_endpoint_connector_mac.cc
index a6bb6519..1ed8928c 100644
--- a/components/named_mojo_ipc_server/named_mojo_server_endpoint_connector_mac.cc
+++ b/components/named_mojo_ipc_server/named_mojo_server_endpoint_connector_mac.cc
@@ -112,8 +112,10 @@
bool NamedMojoServerEndpointConnectorMac::TryStart() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ mojo::NamedPlatformChannel::Options options;
+ options.server_name = options_.server_name;
mojo::PlatformChannelServerEndpoint server_endpoint =
- mojo::NamedPlatformChannel({options_.server_name}).TakeServerEndpoint();
+ mojo::NamedPlatformChannel(options).TakeServerEndpoint();
if (!server_endpoint.is_valid() ||
!server_endpoint.platform_handle().is_valid_mach_receive()) {
return false;
diff --git a/mojo/core/ipcz_driver/invitation.cc b/mojo/core/ipcz_driver/invitation.cc
index 9f808aef..69ec2887 100644
--- a/mojo/core/ipcz_driver/invitation.cc
+++ b/mojo/core/ipcz_driver/invitation.cc
@@ -109,31 +109,38 @@
// given a handle to a connected named pipe. It may return an invalid process
// object if either the handle does not refer to a named pipe or the handle
// refers to a named pipe that is not connected.
-base::Process OpenRemoteProcess(const MojoInvitationTransportEndpoint& endpoint,
- bool remote_is_server) {
- base::ProcessId remote_process_id = 0;
+base::Process OpenRemoteProcess(
+ const MojoInvitationTransportEndpoint& endpoint) {
// Extract the handle to the connected named pipe from mojo invitation
// transport endpoint.
HANDLE handle =
LongToHandle(static_cast<long>(endpoint.platform_handles[0].value));
- auto get_remote_pid = remote_is_server ? &GetNamedPipeServerProcessId
- : &GetNamedPipeClientProcessId;
- // Try to get the remote client process id given the extracted handle via
- // GetNamedPipe(Server|Client)ProcessId API.
- if ((!get_remote_pid(handle, &remote_process_id) ||
- remote_process_id == base::Process::Current().Pid())) {
- DVLOG(2) << "Failed to get remote process id via the connected named pipe";
+
+ base::ProcessId client_pid = 0;
+ base::ProcessId server_pid = 0;
+ base::ProcessId current_pid = base::GetCurrentProcId();
+
+ if (!GetNamedPipeClientProcessId(handle, &client_pid)) {
+ PLOG(ERROR) << "GetNamedPipeClientProcessId failed";
+ return base::Process();
+ }
+ if (!GetNamedPipeServerProcessId(handle, &server_pid)) {
+ PLOG(ERROR) << "GetNamedPipeServerProcessId failed";
return base::Process();
}
- if (remote_process_id == 0) {
- DVLOG(2) << "Remote process id is invalid";
+ // The remote PID is whichever one isn't us.
+ base::ProcessId remote_pid =
+ (client_pid == current_pid) ? server_pid : client_pid;
+
+ if (remote_pid == 0 || remote_pid == current_pid) {
+ DLOG(ERROR) << "Could not identify remote process ID.";
return base::Process();
}
// Try to open the remote process.
base::Process remote_process =
- base::Process::OpenWithAccess(remote_process_id, PROCESS_DUP_HANDLE);
+ base::Process::OpenWithAccess(remote_pid, PROCESS_DUP_HANDLE);
if (!remote_process.IsValid()) {
DVLOG(2) << "Remote process is invalid";
return base::Process();
@@ -287,8 +294,7 @@
// in such case, rely on the connected named pipe to get the remote process
// id, then open and set the remote process.
if (!remote_process.IsValid()) {
- remote_process =
- OpenRemoteProcess(*transport_endpoint, /* remote_is_server= */ false);
+ remote_process = OpenRemoteProcess(*transport_endpoint);
}
#endif
@@ -422,8 +428,7 @@
base::Process remote_process;
#if BUILDFLAG(IS_WIN)
if (is_elevated) {
- remote_process =
- OpenRemoteProcess(*transport_endpoint, /* remote_is_server= */ true);
+ remote_process = OpenRemoteProcess(*transport_endpoint);
}
#endif
if (remote_process.IsValid()) {
diff --git a/mojo/public/cpp/platform/named_platform_channel.cc b/mojo/public/cpp/platform/named_platform_channel.cc
index 078f8aab..e8edd10b 100644
--- a/mojo/public/cpp/platform/named_platform_channel.cc
+++ b/mojo/public/cpp/platform/named_platform_channel.cc
@@ -13,6 +13,9 @@
const char NamedPlatformChannel::kNamedHandleSwitch[] =
"mojo-named-platform-channel-pipe";
+NamedPlatformChannel::Options::Options() = default;
+NamedPlatformChannel::Options::~Options() = default;
+
NamedPlatformChannel::NamedPlatformChannel(const Options& options) {
server_endpoint_ = PlatformChannelServerEndpoint(
CreateServerEndpoint(options, &server_name_));
@@ -45,7 +48,8 @@
PlatformChannelEndpoint NamedPlatformChannel::ConnectToServer(
const ServerName& server_name) {
DCHECK(!server_name.empty());
- Options options = {.server_name = server_name};
+ Options options;
+ options.server_name = server_name;
return CreateClientEndpoint(options);
}
diff --git a/mojo/public/cpp/platform/named_platform_channel.h b/mojo/public/cpp/platform/named_platform_channel.h
index 3633b29..74ccec4 100644
--- a/mojo/public/cpp/platform/named_platform_channel.h
+++ b/mojo/public/cpp/platform/named_platform_channel.h
@@ -40,6 +40,9 @@
#endif
struct COMPONENT_EXPORT(MOJO_CPP_PLATFORM) Options {
+ Options();
+ ~Options();
+
// Specifies the name to use for the server. If empty, a random name is
// generated.
ServerName server_name;
@@ -64,6 +67,12 @@
// Acceptable values are in the range 1 through PIPE_UNLIMITED_INSTANCES
// (255).
size_t max_clients = 1;
+
+ // If |true|, the client will verify that the server process is running
+ // at the same or higher integrity level as the client. This is useful
+ // to prevent named pipe squatting attacks, where a lower-privilege
+ // process attempts to impersonate a trusted server.
+ bool verify_server_privilege = false;
#elif BUILDFLAG(IS_POSIX)
// On POSIX, every new unnamed NamedPlatformChannel creates a server socket
// with a random name. This controls the directory where that happens.
diff --git a/mojo/public/cpp/platform/named_platform_channel_win.cc b/mojo/public/cpp/platform/named_platform_channel_win.cc
index abf32b2..cf96b30 100644
--- a/mojo/public/cpp/platform/named_platform_channel_win.cc
+++ b/mojo/public/cpp/platform/named_platform_channel_win.cc
@@ -17,6 +17,7 @@
#include "base/strings/strcat_win.h"
#include "base/strings/string_number_conversions_win.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/win/access_token.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
@@ -33,6 +34,28 @@
constexpr wchar_t kDefaultSecurityDescriptor[] =
L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;OW)";
+bool VerifyServerPrivilege(HANDLE pipe_handle) {
+ DWORD pid = 0;
+ if (!GetNamedPipeServerProcessId(pipe_handle, &pid)) {
+ return false;
+ }
+
+ base::win::ScopedHandle process(
+ OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid));
+ if (!process.is_valid()) {
+ return false;
+ }
+
+ auto server_token = base::win::AccessToken::FromProcess(process.get());
+ auto client_token = base::win::AccessToken::FromCurrentProcess();
+
+ if (!server_token || !client_token) {
+ return false;
+ }
+
+ return server_token->IntegrityLevel() >= client_token->IntegrityLevel();
+}
+
} // namespace
// static
@@ -133,6 +156,14 @@
DPLOG_IF(ERROR, !handle.is_valid())
<< "Named pipe " << pipe_name
<< " could not be opened after WaitNamedPipe succeeded";
+
+ if (handle.is_valid() && options.verify_server_privilege) {
+ if (!VerifyServerPrivilege(handle.GetHandle().Get())) {
+ DLOG(ERROR) << "Server privilege check failed.";
+ return PlatformChannelEndpoint();
+ }
+ }
+
return PlatformChannelEndpoint(std::move(handle));
}
Original Bug Report
Potential LPE via Named Pipe Squatting and Mojo IPCz Handle Confusion in Google Updater
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the Chrome Security team. Please see go/chrome-ai-generated-security-bugs-faq for more information.
Overview: The Google Updater on Windows connects to a predictable named pipe without verifying the server’s identity, allowing a local attacker to intercept the connection. Due to flaws in how Mojo IPCz handles isolated connections and queries process IDs, the attacker is trusted as a broker, bypassing handle decoding security checks. This allows the attacker to force the SYSTEM-privileged updater to close arbitrary handles.
Affected files:
chrome/enterprise_companion/enterprise_companion_client.ccmojo/core/ipcz_driver/transport.ccmojo/core/ipcz_driver/invitation.ccmojo/public/cpp/platform/named_platform_channel_win.ccchrome/updater/policy/policy_fetcher.cc
Estimated timestamp from git blame: 2025-12-18
Description
A potential local privilege escalation (LPE) vulnerability exists in the Google Updater on Windows. When the SYSTEM-privileged updater attempts to connect to the Chrome Enterprise Companion App (CECA), it does so over a named pipe with a predictable name and fails to verify the identity of the server. This allows a local, unprivileged attacker to squat the pipe and act as a malicious server.
Due to the way the updater establishes this connection (mojo::IsolatedConnection), Mojo IPCz classifies the connection as broker-to-broker. Furthermore, a logic error in OpenRemoteProcess causes the updater to query its own process ID instead of the attacker’s, leaving the remote process handle invalid. These conditions inadvertently bypass critical security checks in IPCz handle decoding, granting the attacker the ability to pass arbitrary handle values that the SYSTEM process will then close via base::win::ScopedHandle destruction. This provides a reliable Arbitrary CloseHandle primitive, which is a known vector for privilege escalation.
Technical Details
-
Named Pipe Squatting: The updater connects to
\\.\pipe\mojo.ChromeEnterpriseCompanionServiceviaConnectWithRetries(). The connection logic (mojo::NamedPlatformChannel::CreateClientEndpoint) usesSECURITY_ANONYMOUSto prevent impersonation but does not verify the identity (e.g., owner SID or process signature) of the server that created the pipe. Windows named pipes are first-come-first-served, so an unprivileged attacker can create this pipe before the legitimate CECA server does. -
Broker Trust via Isolated Connection: The updater wraps the connection in a
mojo::IsolatedConnection. When this is passed down to IPCz viaOutgoingInvitation::SendIsolated(), theMOJO_SEND_INVITATION_FLAG_ISOLATEDflag causesInvitation::Send()to set the transport’sdestinationtype toTransport::kBroker. -
Invalid Remote Process via Logic Flaw: Because
IsolatedConnectiondoes not explicitly provide the remote process,Invitation::Send()attempts to derive it by callingOpenRemoteProcess(*transport_endpoint, /* remote_is_server= */ false). Becauseremote_is_serveris false, it callsGetNamedPipeClientProcessId. However, the updater is the client of this named pipe. It receives its own PID, detects the mismatch, and returns an invalidbase::Process. Consequently, the transport is created with an invalidremote_process. -
Handle Verification Bypass: When the attacker sends an IPCz message, the handles are decoded in
Transport::DecodeHandle(). The attacker can specifyHandleOwner::kRecipientfor a handle. The security check designed to prevent untrusted peers from sendingkRecipienthandles is:if (from_transport.destination_type() != Transport::kBroker && !from_transport.is_peer_trusted() && !remote_process.is_current()) { return std::nullopt; }Because the destination type was set to
Transport::kBroker(Step 2), this check is entirely bypassed. -
Arbitrary CloseHandle: Because the check is bypassed,
DecodeHandletakes the attacker’s arbitrary 64-bit value, calls::GetHandleInformationto verify the handle exists in the local (SYSTEM) process, and wraps it in abase::win::ScopedHandle(held byPlatformHandle). If the attacker intentionally crafts a malformed message so thatTransport::DeserializeObject()fails, thePlatformHandleobjects are destroyed. The destruction of theScopedHandleinvokes the Windows API::CloseHandle()on the attacker-controlled value.
Potential Attack Steps
Note: Our tooling agent cannot run code, so these are suggested steps based on static analysis.
- As a non-admin user, create a named pipe at
\\.\pipe\mojo.ChromeEnterpriseCompanionService. - Wait for the scheduled task or invoke the COM method (
IUpdater::FetchPolicies) to trigger the SYSTEM updater to connect to the pipe. - Upon connection, send a serialized Mojo IPCz message (e.g.,
ConnectFromBrokerToBroker). - Include handle data in the message with
handle_owner = kRecipientand raw values corresponding to valid handles inside the SYSTEM process (e.g., small multiples of 4 like0x4,0x8,0xC). - Intentionally malform the rest of the message so that deserialization fails.
- The SYSTEM updater processes the message, wraps the handles, fails deserialization, and automatically closes the attacker-specified handles, disrupting the process or opening a window for LPE via handle re-use.
Suggested Fix
- Verify Server Identity: Modify
named_mojo_ipc_server::ConnectToServerormojo::NamedPlatformChannel::CreateClientEndpointto verify the process ID, owner SID, or digital signature of the server process after successfully connecting to the named pipe. - Fix PID Query Logic: Update
OpenRemoteProcessinmojo/core/ipcz_driver/invitation.ccto ensure that when a client is attempting to verify a peer, it usesGetNamedPipeServerProcessId, and vice versa. - Review Isolated Connection Trust: Re-evaluate whether
IsolatedConnectionshould unconditionally set thedestination_typetoTransport::kBroker, especially when the remote process is unknown or unverified.
Evaluated with Chrome root at commit: 7353d249d9cacf9c7218e1d7b8a39cf39c72d646
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.