CreateProcess search order turns an executable name into a trust decision
Windows CreateProcess can launch an executable by name or by full path. When the caller supplies a name without a directory, the operating system resolves it through a search sequence that includes locations beyond the caller's explicit directory. That behavior is convenient for interactive tools and risky for a privileged service that inherits an attacker-influenced working directory or environment.
Microsoft's CreateProcessW documentation lists the search sequence used when the file name does not contain a path. It includes the application's directory, the current directory, system directories, the Windows directory, and directories in PATH in the documented order. The exact sequence matters, but the security decision is simpler: a privileged caller should not let an untrusted environment choose which executable runs.
CWE-426 describes the broader weakness: a product searches for a critical resource using an externally supplied path that can point outside its control. CWE-427 covers a related case where the search path is fixed but an element in it is writable by an attacker. Both are relevant when a service launches helpers, shells, backup tools, or maintenance scripts.
How the path becomes exploitable
The classic pattern is a privileged service with a working directory in a user-writable location. It calls an executable by bare name, and the attacker drops a file in a directory that appears earlier in the search sequence than the intended program. If the service has already accepted an untrusted file name, the same confusion can occur without the working directory being globally writable.
lpApplicationName and the command line need consistent handling. If the application name is null, the first token of the command line may be parsed as the module name, which can change how spaces, quotes, and arguments are interpreted. A wrapper that concatenates strings and re-parses them is harder to review than a structured argument list passed to a well-defined launcher.
Inventory the launch points
Search source code, services, scheduled tasks, installers, and update agents for calls to CreateProcess, ShellExecute, system, and language wrappers that ultimately use the Windows process API. Record whether the executable path is absolute, who can write to each directory, and which environment the child inherits.
Look for bare helper names such as powershell, cmd, rundll32, msiexec, or project-specific tools. A bare system utility can still be a problem if the current directory or a custom path entry is writable. Check service working directories and any temporary directory used during updates. Review the ACLs rather than assuming a directory is protected because it is under a system-looking path.
Prefer explicit identity
Resolve trusted executables from a protected location and pass the full path. Keep the executable, its directory, and its configuration writable only by administrators or the application's dedicated service account. Do not allow tenant data, uploaded archives, or user-controlled environment variables to set the working directory.
Sanitize environment blocks before launching a privileged child. In particular, do not inherit a path that an unprivileged process can modify. Use an allow-list of environment variables and a known starting directory. When a wrapper must accept a tool name, map the name to a fixed registry of approved executables instead of asking the operating system to search.
Verify the resolved file's ownership, ACL, signature, and hash where the threat model requires code integrity. Hashing a file after a search does not prove that the search selected the intended location, so record the absolute path and the resolution result as well.
Test and monitor
Use an isolated service account and create a harmless test executable in a directory that would appear earlier in the search order. Confirm that the service either rejects the path or launches the intended protected binary. Repeat with an inherited PATH, a changed working directory, and a command line containing spaces.
Alert on process creation from user-writable directories, especially by privileged service accounts. Correlate the parent process, image path, command line, and working directory. The control is a stable executable identity, not a trusted-looking filename.
Top comments (0)