{
	"id": "dc14bac0-724e-4e07-865e-dab14de997a1",
	"created_at": "2026-04-06T00:16:35.59643Z",
	"updated_at": "2026-04-10T03:21:36.512161Z",
	"deleted_at": null,
	"sha1_hash": "bba08fc1e1acc3c6f63e383dcad12f7449a015f0",
	"title": "How We Found a PATH Vulnerability in Windows | ExpressVPN Blog",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1377227,
	"plain_text": "How We Found a PATH Vulnerability in Windows | ExpressVPN Blog\r\nBy The PATH to NT Authority/System\r\nArchived: 2026-04-02 10:51:33 UTC\r\nEditor’s note: This post is part of our series for cybersecurity professionals and hobbyists, written by ExpressVPN's\r\ncybersecurity team.\r\nIn one of our regular security audits of ExpressVPN applications, we surfaced an interesting vulnerability. It wasn't found\r\nwithin our own codebase but stemmed from the use of .NET Core itself which, in the worst case, could result in privilege\r\nescalation on the Windows platform. However, the vulnerability could only be exploited if one of the controversial security\r\nboundaries was violated: the writable directory in PATH. \r\nIn this article, we will explain in detail the PATH environment variable and the security implications of having it\r\nmisconfigured, and shed light on some of our findings in this space.\r\nThis PATH vulnerability issue was found during an audit of a closed beta version of our product for Windows not available\r\nto consumers. We remediated the issue after we discovered it and disclosed the discovery to Microsoft.\r\nWhat is the PATH environment variable?\r\nWhen a user tries to run a program from the command line interface (CLI), Windows needs to know the true location of the\r\nprogram in order to execute it. In our example below, we attempt to run ping. Windows doesn’t immediately know where\r\nping is located, but it still manages to find it.\r\nhttps://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nPage 1 of 9\n\nInternally, Windows looks up the location through the PATH environment variable. The PATH environment is a semi-colon\r\n(;) delimited list of directories, like the one below.\r\nC:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;C:WindowsSystem32OpenSSH;C:Pr\r\nFilesMicrosoft SQL Server130ToolsBinn;C:Program\r\nFilesdotnet;C:UsersUserAppDataLocalMicrosoftWindowsApps;;C:UsersUserAppDataLocalProgramsMicrosoft VS\r\nCodebin;C:UsersUser.dotnettools\r\nWe note that PATH encompasses both the PATH environment variable for the system and the user, though for simplicity’s\r\nsake the rest of the article will focus on the system’s PATH environment variable. In our example, Windows searches each of\r\nthe paths down the list for executables with the basename of ping, and executes the first one that matches (case insensitive).\r\nHere, the executable was found in the first entry of PATH, C:Windowssystem32, and C:WindowsSystem32PING.EXE is\r\nexecuted.\r\nOne can think of a PATH as a list of trusted places in which Windows can look up programs to execute. This isn’t just\r\nlimited to the command line; Windows itself relies on the PATH environment variable to load dependencies, particularly\r\ndynamic link libraries (DLLs). If a certain DLL cannot be found, the PATH can be traversed to find the DLL.\r\nPATH: An unmonitored attack surface\r\nNeedless to say, strict rules should be enforced on the paths in PATH for them to be considered trustworthy. In particular, if\r\nthe contents of any of the directories in PATH can be modified by any unprivileged local/remote user, then all bets\r\nare off. Unfortunately, any administrator can haphazardly add directories into the PATH variable with no security checks\r\nperformed by the operating system whatsoever. This can happen for a number of reasons:\r\n1. User error: An administrator wishes to invoke a certain program just by its base name on the command line and\r\nadds the directory where the program resides without first checking the permissions on the directory.\r\n2. Vulnerable installation: During the installation process, a benign program adds a directory with incorrect access\r\ncontrols to the PATH environment variable without locking down the permissions on that directory. Security\r\nresearchers have surfaced vulnerabilities of this type in recent years, for example CVE-2020-12510.\r\nThere is much confusion on whether having a world-writable directory in PATH is a security risk. We definitively prove that\r\nit is a security risk with attack scenarios described below.\r\nWe present a roadmap to escalate privileges on the local machine, given a writable directory in PATH. Specifically, in the\r\nfollowing attack scenarios, we assume the following are true:\r\n1. The victim is running Windows\r\nhttps://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nPage 2 of 9\n\n2. A directory listed in PATH is writable by any user\r\n3. The attacker has the ability to write files to the directory in 2)\r\nScenario 1: PATH interception—search order hijacking\r\nThis exploitation scenario comes as a natural extension of how the PATH variable is used. Suppose an administrator\r\nregularly uses a custom program (clean.bat) to do administrative operations. He adds the directory it resides in, C:tools, to\r\nthe system PATH variable for ease of invocation during his normal duties. The program runs when he invokes clean, and he\r\nhappily goes off to perform his other duties.\r\nUnbeknownst to him, the folder C:compiler in the PATH variable is world-writable, and its order in the PATH is much\r\nearlier than the program’s true location. A malicious user notices and writes a script with the same name into the C:compiler\r\nfolder. The next time the administrator runs clean from the command line, the clean program in C:compiler is executed:\r\nFrom there, the administrator account is compromised—all it takes is to bypass User Account Control (UAC), which isn’t a\r\nsecurity guarantee and is trivially bypassable.\r\nThis technique is known as search order hijacking, where a malicious binary found earlier in the PATH variable executes\r\nin place of the expected benign executable. A surreptitious attacker can ensure that the original program is called after the\r\npayload is executed, meaning that the administrator would be none the wiser.\r\nNote that this doesn’t only apply to commands that are run by the administrator, but also by scripts and programs that invoke\r\nthe shell to run a command. If any program or script isn’t careful about how they are invoking other programs, then this\r\nvulnerability can be triggered. \r\nhttps://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nPage 3 of 9\n\nDuring internal testing of a pre-release build of the Windows ExpressVPN application, we found such invocations which\r\ncould be exploited when a directory in PATH is writable. During installation, the program needed to find the installed\r\nversions of the .NET runtimes and install the missing runtimes. If we look at the documentation, the “recommended” way is\r\nto invoke the dotnet executable, which programmatically would look like this: \r\n```\r\nvar process = new Process\r\n{\r\nStartInfo = new ProcessStartInfo(“dotnet”, \"--list-runtimes\")\r\n{\r\nUseShellExecute = false,\r\nRedirectStandardOutput = true,\r\nRedirectStandardError = true\r\n}\r\n};\r\nprocess.Start();\r\nprocess.WaitForExit();\r\nreturn process.StandardOutput.ReadToEnd();\r\n```\r\nIn this case, because dotnet is found through the PATH environment variable, the search order can be hijacked and the\r\nmalicious binary can run in its place. Our developers quickly triaged and remediated the issue by only loading dotnet from\r\ntrusted installation paths, preventing such exploit techniques from working even when there is a writable directory in the\r\nPATH environment variable.\r\nScenario 2: DLL search path hijack on an external privileged application\r\nDynamic-Link Libraries (DLLs) are dependencies of an application packaged into their own binary file. This allows code to\r\nbe shared without having multiple instances of the same code spread across files. When an application needs to invoke a\r\nmethod from one of these libraries, they load the DLL into memory and execute the relevant function in the DLL. Because\r\ncode is executed from the DLL, it must be trusted and cannot be arbitrarily loaded.\r\nWhen a Windows application loads, some DLLs may be missing at the start. In this case, the application will try to look for\r\nmissing DLLs that it needs in the following manner:\r\nby first looking at the directory it was loaded from (where the application resides)\r\nlooking at the current directory\r\nthe system directory\r\nthe Windows directory\r\nsearching in the directories listed in the PATH environment variable\r\nIn ordinary circumstances, this behavior is warranted. Developers are able to prevent their application from loading outside\r\nof the desired directories by making sure that they include all dependencies which the program needs in the folder where the\r\nprogram resides. \r\nHowever, this isn’t always the case, if Windows doesn’t find the DLL it needs, it can fall back to loading from the\r\ndirectories of the PATH environment variable. This can be hijacked by a malicious user with write access to a directory in\r\nPATH, using a technique known as Phantom DLL Hijacking. We list two case studies below where privileged applications\r\n(e.g., drivers, services) show this behavior.\r\nThe curious case of the driver\r\nhttps://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nPage 4 of 9\n\nIn July 2020, we received a submission from a BugCrowd researcher claiming to have found a privilege escalation for our\r\nWindows application. The researcher provided the following proof that ExpressVPN was loading the igdgmm32.dll from a\r\ndirectory in the PATH environment variable.\r\nThe initial triage conducted by Bugcrowd was unable to reproduce the finding. Our internal triage team then took a look to\r\nensure we do not miss any valid findings. We first studied the impact of the issue; ExpressVPN.exe never runs in a\r\nprivileged context and only as the current user, so the privilege escalation would be lateral in the worst case (from one\r\nuser to another user). However, we do not rule out the possibility of a path to successful privilege escalation; one could\r\nattempt to compromise the administrator running ExpressVPN.exe from another non-privileged user account on the same\r\nmachine.\r\nNext, we looked at the prerequisites for exploitation to be successful. The installation process of ExpressVPN ensures that\r\nthe correct access controls are set for the folders that are created. This means that the folders where ExpressVPN.exe\r\nresides are not writable by non-privileged users. The proof-of-concept the researcher provided loads from C:Python38, a\r\ndirectory unrelated to ExpressVPN and which was already world-writable to begin with, likely due to a misconfiguration on\r\nthe Administrator’s part. This means most of our users are not impacted unless they have a world writable directory to begin\r\nwith.\r\nWe then dug deeper into the underlying issue. On our virtual machine testbeds, we similarly could not reproduce the finding,\r\nbut we were convinced that it was possible thanks to the Procmon logs provided by the researcher. We investigated the DLL\r\nitself, and found that igdgmm32.dll is part of the Intel HD Graphics Drivers package. From there, we quickly isolated the\r\nissue and found this article on DLL Hijacking. It turns out that the driver is loaded as part of the Windows Presentation\r\nFoundation (WPF) UI framework (a framework used to build Windows UI applications), and this only occurs when the\r\nsystem chipset used belongs to Intel. Indeed, this was the missing dependency that was causing the library to load from the\r\nPATH environment variable.  \r\nUnfortunately, in this case, because the underlying problem impacts any application that uses the Windows\r\nPresentation Foundation UI framework, there’s very little that can be done on our end short of the mitigations we already\r\nhave in place. A complete fix would require the vendor to patch the issue. \r\nWe contacted both Microsoft and Intel on the issue, crediting the original researcher for the discovery. Microsoft claimed it\r\nwasn’t under their purview and nudged us towards notifying Intel. Intel investigated the issue and found that the issue raised\r\nin the report was present in an older version of the driver (26.20.100.7262), and the latest version at the time\r\n(27.20.100.8476) no longer had the issue. \r\nEven without a vendor patch, it is important to emphasize that this can only occur if a directory in PATH is writable, which\r\nby default isn’t the case, so we reiterate the importance of checking your PATH.\r\nO dependency, where art thou?\r\nIn our second case study, we examine a vulnerability found during an audit of our next-generation Windows application\r\n(pre-release). During our testing, we observed the dependencies loaded via Procmon; one dependency caught our attention -\r\nhttps://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nPage 5 of 9\n\nMicrosoft.DiaSymReader.Native.amd64.dll. We noticed it was loaded every time a service belonging to our application\r\nstarted or restarted.\r\nMuch like the DLL hijacking above, the DLL can be hijacked and loaded from a directory in the PATH environment\r\nvariable. The AppService was running as NT AUTHORITYLOCAL SERVICE, which by default isn’t privileged. However,\r\nbecause of improper permission boundaries in Windows, if we can get code execution on the AppService via planting a\r\nmalicious DLL in a writable PATH directory, we can leverage one of the existing bypasses to escalate privileges to NT\r\nAUTHORITYSYSTEM. This is unfortunate because while NT AUTHORITYLOCAL SERVICE was designed to have less\r\nprivileges, due to the complexity of the Windows operating system, not all privilege escalation paths are covered. Those\r\ninterested can read more about the privilege escalations possible here. \r\nOur development team investigated for some time, but there was no reference to this library anywhere in our codebase.\r\nSomehow or somewhere, something was loading this DLL, and we had to get to the bottom of it to identify the root cause\r\nand protect our users.\r\nWe then did something quite extreme. From the original codebase, they took out large chunks of the code, recompiled, then\r\nran the program to see if the DLL was still loaded. Through this, we were effectively able to “binary search” through the\r\ncodebase to identify the root cause. As it turns out, Microsoft.DiaSymReader.Native.amd64.dll was loaded because an\r\nunhandled exception was thrown in the program. The offensive security team quickly created a proof of concept below.\r\nnamespace PoC\r\n{\r\npublic class Program\r\n{\r\npublic static void Main(string[] args)\r\n{\r\nvar a = args[100]; // triggers IndexOutOfRangeException\r\n}\r\n}\r\n}\r\nWe executed the PoC, and lo and behold, Microsoft.DiaSymReader.Native.amd64.dll was loaded! \r\nWe reported the issue to Microsoft on January 5, 2021. On January 21, Microsoft determined that the vulnerability did not\r\nmeet the bar for servicing because “Adding folders to the PATH variable requires administrator rights, and all default\r\nfolders that are included in the PATH variable require administrator permissions to modify.” This is consistent with how\r\nthey handled similar vulnerabilities in the past (more information on this in Scenario 3).\r\nhttps://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nPage 6 of 9\n\nThe development team, upon realizing the issue, remediated it immediately by packaging the missing DLLs with the\r\ninstallation. The files Microsoft.DiaSymReader.Native.amd64.dll for the 64-bit version and\r\nMicrosoft.DiaSymReader.Native.x86.dll for the 32-bit version are installed in the application folder where the service\r\napplications reside so the files will no longer be loaded from PATH. This means that our application remains safe,\r\nregardless of Microsoft’s decision to publish a patch for this issue.\r\nScenario 3: DLL search path hijack on default Windows applications \r\nEven if you choose to install nothing on your machine, some in-built Windows applications may themselves be prone to\r\nDLL Hijacking. Security researchers have extensively studied this exploitation technique and published detailed findings on\r\ndifferent scenarios in which this can be exploited. Windows applications tend to run as privileged services or applications, so\r\nan exploitable DLL Hijack would allow a user to run code as that application to escalate privileges. The prerequisite, as\r\nalways, is that a directory in PATH is writable for our less-privileged user.\r\nWhat is particularly striking is not the existence of such issues, but the vendor’s stance towards fixing this issue. There are\r\ntwo widely known targets where this could be exploited, one that works for Windows 8 and below and another that works\r\nfor Windows 10. For both of these issues, Microsoft deemed that they did not meet the bar for servicing. We note that the\r\nformer exploit technique was mitigated silently in 2013 with the release of Windows 8.1, while no news of patches for the\r\nlatter. There is no defense in depth: Once a machine has a PATH directory without proper access controls, a malicious\r\nprocess/user can easily escalate privileges and perform any kind of malicious activity as it pleases.\r\nWhat does this mean for the end user?\r\nAs of April 2018, Microsoft has made it clear that vulnerabilities that require a directory in PATH to be writable are not\r\nvulnerabilities since the directories there should never be world-writable, and if they were, then it is the fault of the\r\nadministrator or application that made that change. As seen in Scenarios 2 and 3, exploitation techniques that leverage the\r\nwritable PATH directories are unlikely to be mitigated by official patches, so it is up to end users to enforce that all\r\ndirectories in PATH have the proper access controls in place.\r\nThankfully, such vulnerabilities aren’t common. Users rarely change the system PATH environment variable, and it is even\r\nrarer for them to specify a world-writable directory there, though that is definitely possible. It is more likely that an\r\ninstallation process introduces a vulnerability. However, from our quick investigation of approximately 100 of the top\r\napplications for Windows from various download sites, none of the installations introduced this vulnerability.\r\nHere at ExpressVPN, we put in place in-depth defensive measures to ensure that even if the PATH contains a writable\r\ndirectory, our applications never load code from such directories. We do so by ensuring that executables are run from trusted\r\npaths, along with mitigating DLL planting vulnerabilities when necessary.\r\nNevertheless, one can never be too careful. To that end, we have created a simple PowerShell script which you can use to\r\naudit your system. As with any script you find on the internet, read through carefully to make sure you understand what it is\r\ndoing. \r\nYou can run the script as a low privilege user to see if any of the directories in the system PATH are writable, and the script\r\noutputs the writable directories into the command line, as below: \r\nYou can secure yourself by removing such directories from your system PATH, or by appropriately changing the\r\npermissions of the directories listed. Once that’s done, you can re-run the script and check the results to make sure your\r\nsystem is truly hardened!\r\nhttps://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nPage 7 of 9\n\nIt’s important for users to stay vigilant in protecting their privacy and security. We believe in empowering users and enabling\r\nthem to protect themselves by arming them with the tools and technologies to do so. Our discussion on PATH vulnerabilities\r\nshould dispel some myths and we hope that our script has helped our readers identify vulnerabilities on their machines\r\nbefore they can be exploited by malicious actors.\r\nfunction Test-Administrator\r\n{\r\n$domain, $userToFind = [String]([Security.Principal.WindowsIdentity]::GetCurrent().Name) -Split ''\r\n$administratorsAccount = Get-WmiObject Win32_Group -filter \"LocalAccount=True AND SID='S-1-5-32-544'\"\r\n$administratorQuery = \"GroupComponent = `\"Win32_Group.Domain='\" + $administratorsAccount.Domain +\r\n\"',NAME='\" + $administratorsAccount.Name + \"'`\"\"\r\n$user = Get-WmiObject Win32_GroupUser -filter $administratorQuery | select PartComponent |where {$_ -match\r\n\"$domain\"} |where {$_ -match \"$userToFind\"}\r\n$user\r\n}\r\nif (Test-Administrator) {\r\nWrite-Host \"Please run as a low privilege user for accurate results.\"\r\nExit 1\r\n}\r\nfunction Is-Writable-Folder {\r\nparam (\r\n[parameter(Mandatory=$True)]\r\n[string]$Folder\r\n)\r\n if (Test-Path \"$Folder\" -IsValid) {\r\n# folder exists\r\n$TestFile = \"__test_PATH_$(get-date -f MM-dd-yyyy_HH_mm_ss).tmp\"\r\n$TestFilePath = Join-Path -Path $Folder -ChildPath $TestFile\r\nTry {\r\n[io.file]::OpenWrite($TestFilePath).close()\r\n[io.file]::Delete($TestFilePath)\r\nreturn $true\r\n} Catch {\r\nreturn $false\r\n}\r\n} else {\r\nreturn $false\r\n}\r\n}\r\n$AllPaths = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession\r\nManagerEnvironment' -Name PATH).Path.Split(\";\")\r\n$WritablePaths = @()\r\nForeach ($path in $AllPaths)\r\n{\r\nTry {\r\n$path = $path.Trim()\r\nhttps://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nPage 8 of 9\n\nif ($path.Length -gt 0) {\r\nif (Is-Writable-Folder($path)) {\r\n$WritablePaths += $path\r\n}\r\n}\r\n} Catch {\r\nWrite-Host \"Error processing: '$path' - not a valid directory\"\r\n}\r\n}\r\nIf ($WritablePaths.count -eq 0) {\r\nWrite-Host \"No writable directories in system PATH found!\"\r\n} Else {\r\nForeach ($path in $WritablePaths) {\r\nWrite-Host \"'$path' is writable!\"\r\n}\r\n}\r\nPause\r\nSource: https://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nhttps://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/\r\nPage 9 of 9",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://www.expressvpn.com/blog/cybersecurity-lessons-a-path-vulnerability-in-windows/"
	],
	"report_names": [
		"cybersecurity-lessons-a-path-vulnerability-in-windows"
	],
	"threat_actors": [],
	"ts_created_at": 1775434595,
	"ts_updated_at": 1775791296,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/bba08fc1e1acc3c6f63e383dcad12f7449a015f0.pdf",
		"text": "https://archive.orkl.eu/bba08fc1e1acc3c6f63e383dcad12f7449a015f0.txt",
		"img": "https://archive.orkl.eu/bba08fc1e1acc3c6f63e383dcad12f7449a015f0.jpg"
	}
}