Securing Windows Named Pipes
Attackers target Windows named pipes; developers must verify identities, permissions, and data.
Windows named pipes are a well-worn path for interprocess communication on a single machine, favored for their speed and OS-level support. But cybersecurity experts warn that developers often treat these local pipes as implicitly trusted, overlooking the reality that a workstation is a crowded, multi-user environment where any process with the right handle can knock on the pipe's door.
Local Does Not Mean Trusted
Named pipes are not private by default. A typical Windows box runs processes under LocalSystem, administrators, standard users, and service accounts, alongside third-party software, scripts, and potentially malware under a compromised account. Any process that knows the pipe name and holds sufficient access rights can attempt to connect. Windows does not inherently know which executable the developer intended to use the pipe.
This makes a named pipe an exposed local interface. Before processing any request, an application must determine who connected, what that identity is allowed to do, and whether the supplied data is safe.
The Privilege Boundary
The risk escalates when a privileged Windows service communicates with a less privileged desktop application. A service running as LocalSystem may modify protected files, launch processes, change system configuration, access other users' data, or talk to kernel drivers. When such operations are exposed through a named pipe, the pipe becomes an API to privileged functionality.
A successful connection only proves the client was allowed to open the pipe. It does not prove the client is the expected application, that the connected user is authorized, that the requested operation is permitted, or that the supplied command is safe. Pipe permissions should therefore be defined explicitly and restricted to the smallest appropriate set of identities. Broad permissions for Everyone, Authenticated Users, or all interactive users may allow unrelated processes to reach the pipe.
Authentication and authorization must remain separate. A user may be allowed to query service status but not stop the service, change protected settings, launch processes, or access arbitrary files. Sensitive commands should be authorized individually.
Impersonation can help by performing operations under the client's security context, but it must be handled carefully. The server should verify that impersonation succeeded, limit the work performed while impersonating, and always restore its original identity.
Untrusted Servers, Commands, and Data
The client must verify the server just as the server verifies the client. A predictable pipe name is only an identifier, not a secret. An attacker may create a pipe using the expected name before the legitimate server starts, causing the client to connect to an attacker-controlled process. The first-pipe-instance option can help detect that the name has already been claimed, but it does not replace proper access controls or server identity verification.
Messages received through the pipe must also be treated as untrusted input, even from authenticated clients. Attackers can send malformed or oversized payloads, invalid file or registry paths, unsupported command combinations, corrupted serialized objects, or values designed to trigger error conditions. A privileged service that converts such input directly into file, registry, process, or command-line operations may become a confused deputy: the attacker supplies the instruction, while the service supplies the privileges.
Requests should use strict message framing, bounded sizes, command allowlists, schema validation, path normalization, operation-specific authorization, and safe error handling.
Availability and Remote Exposure
Named-pipe security is not limited to privilege escalation and unauthorized commands. A malicious or malfunctioning process may repeatedly connect, hold connections open, send incomplete messages, or submit requests that consume excessive CPU, memory, or kernel resources. The server should use connection limits, timeouts, cancellation, bounded message sizes, controlled concurrency, and rate limiting where appropriate.
It is also unsafe to assume that every named pipe is reachable only from the local computer. Windows named pipes can support remote access in some configurations. Pipes intended exclusively for local IPC should explicitly block network identities such as NT AUTHORITY\NETWORK, or use a mechanism that guarantees local-only communication.
The correct threat model is simple: every named-pipe connection should be considered potentially hostile until the client or server identity, permissions, requested operation, and message contents have all been verified.
When a Named Pipe Becomes a Security Boundary
A named pipe becomes a security boundary when the processes on its two ends run with different privileges or operate under different trust levels. A common example is a Windows service running as LocalSystem and a desktop application running under a standard user account. The service may be able to modify protected files and registry keys, start processes, change system-wide configuration, access data belonging to other users, or communicate with a kernel driver. The desktop application normally cannot perform those operations directly.
When the service accepts commands through a named pipe, the pipe becomes an interface to those privileged capabilities. Any weakness in the pipe's permissions, identity checks, command validation, or authorization logic can allow an untrusted local process to misuse the service's privileges.
A successful connection does not prove that the client is the expected application. It proves only that the connecting process had sufficient permission to open the pipe. Another process running under the same user account may have exactly the same access. The server must therefore validate the security identity behind the connection rather than relying on the process name, executable path, or secrecy of the pipe name.
The server must also authorize each operation separately. A client that is allowed to request service status should not automatically be allowed to stop the service, modify protected configuration, launch a process, or request access to an arbitrary file. Authentication determines who connected; authorization determines what that identity may do.
This distinction is especially important when the server processes client-controlled paths, command-line arguments, registry locations, executable names, or serialized commands. Without strict validation, the service can become a confused deputy: the client chooses the action, but the privileged service performs it.
For example, a seemingly harmless request such as:
- Read file: C:\ProgramData\Product\status.json
may become dangerous if the client can replace the path with:
- Read file: C:\Windows\System32\config\SAM
The same problem applies to requests that start processes, delete files, update registry values, install components, or communicate with a driver. The service must not merely validate that the command is syntactically correct. It must verify that the connected identity is permitted to perform that exact operation against that exact resource.
A secure named-pipe server should therefore apply several checks before executing a privileged request:
- verify the connected client's Windows identity;
- restrict access through an explicit pipe security descriptor;
- authorize each command independently;
- validate all paths, arguments, identifiers, and payload sizes;
- reject unsupported or ambiguous operations;
- avoid exposing general-purpose privileged functionality.
The last point is critical. A command such as "write this value to any registry key" creates a much larger attack surface than a narrowly defined command such as "update this specific application setting." The more general the pipe protocol becomes, the more closely it resembles a privileged local API—and the more carefully it must be secured.
The correct design principle is straightforward: the pipe server must never perform an operation solely because a connected client requested it. It should perform the operation only after confirming who requested it, whether that identity is authorized, and whether the request stays within narrowly defined security boundaries.
Access Control and Client Authorization
A named-pipe server should decide who may connect before it begins processing messages. This starts with an explicit security descriptor that grants access only to the required Windows identities, such as a particular user SID, service account, administrator group, or logon session.
The pipe's DACL controls access to both ends of the named pipe. When a client attempts to connect, Windows compares the client's access token and requested rights with that DACL. Relying on the default descriptor is risky because its permissions may be broader than the application requires.
Access to the pipe does not automatically authorize every available command. A client may be allowed to retrieve status information while being denied permission to modify configuration, start processes, or access protected files. Authorization should therefore be performed for each sensitive operation rather than only once when the connection is established.
Verifying the Peer Process
For local application-to-application communication, the applications can also inspect the process associated with the opposite end of the pipe. The server can call GetNamedPipeClientProcessId; the client can call GetNamedPipeServerProcessId. These Windows APIs return the process identifier associated with the connected client or server. They should be called only after the pipe connection has been established.
The following C# helper retrieves the peer PID using native Windows APIs:
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetNamedPipeClientProcessId(SafePipeHandle pipe, out uint clientProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetNamedPipeServerProcessId(SafePipeHandle pipe, out uint serverProcessId);We can also call another function from kernel32.dll, QueryFullProcessImageName, to retrieve the executable path from a process handle opened with PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION. The returned path can then be compared with the expected executable location as an additional verification step.
On the server side, verification should occur immediately after accepting the connection and before reading or executing commands. The expected executable should be located in a directory that standard users cannot modify. Otherwise, an attacker may replace the file while retaining the expected path. For stronger verification, the application can additionally validate the executable's Authenticode signature or compare it with an approved cryptographic hash.
Why This Matters for Developers
Named pipes are a feature that many Windows developers implement without a second thought, but this guidance shows the hidden complexity. The advice reinforces that a named pipe is not a private channel; it is an exposed interface that must be secured like any other network-facing API.
Developers building or maintaining Windows services that use named pipes should audit their current implementations against these principles. The stakes are real: a single overlooked permission or missing validation could allow a local attacker to elevate privileges, steal data, or compromise system integrity. The good news is that following the steps outlined here—defining explicit access controls, authorizing each operation, validating all input, and verifying the peer process—can significantly reduce the attack surface and keep named-pipe communication safe.
Sources
- BleepingComputer Original source
Continue Reading
Car head units hijacked for proxy botnet abuse
Supply-chain attack on Android car head units turns them into proxy nodes and ad fraud tools.
Android Malware Hijacks VPN to Silence Google Play
ToxicPanda 2.0 uses VPN permissions to block Google Play, adding 167 commands and targeting 349 apps.
Banking Trojans Evolve With New Tricks
Manic, Grandoreiro, and ToxicPanda 2.0 show how banking malware is becoming more sophisticated.