Unquoted Service Paths: The 20-Year-Old Privilege Escalation Still Lurking on Windows Fleets
Unquoted service paths let a low-privileged user drop a malicious binary that Windows runs as SYSTEM. Here's how the bug works, how to find it at scale, and how WinSentinel flags it.
Some vulnerability classes never die — they just keep shipping inside third-party installers. The unquoted service path is the poster child. It has been documented since at least 2005, it is trivial to exploit, and yet a fresh scan of almost any real-world Windows fleet will turn up a handful of vulnerable services, usually from line-of-business software, printer drivers, or in-house tooling that nobody has touched in years.
What the bug actually is
When Windows registers a service, it stores the command line to launch in the ImagePath value under HKLM\SYSTEM\CurrentControlSet\Services\<name>. If that path contains spaces and is not wrapped in quotes, the Service Control Manager has to guess where the executable name ends and the arguments begin. It resolves the ambiguity by walking the path left to right, trying each space-delimited prefix as an .exe.
Consider a service configured like this:
C:\Program Files\Acme Agent\bin\service.exe
With no quotes, Windows attempts to launch, in order:
C:\Program.exe
C:\Program Files\Acme.exe
C:\Program Files\Acme Agent\bin\service.exe
The first candidate that exists wins. So if an attacker can write C:\Program.exe or C:\Program Files\Acme.exe, the Service Control Manager will happily execute their binary — and because most services run as LocalSystem, it runs with the highest privilege on the machine.
Why it's still a real privilege escalation
The catch is write access. C:\ and C:\Program Files\ are protected by default, so this is not a one-click exploit on a well-configured box. But three common conditions turn it into a reliable SYSTEM escalation:
- The vulnerable service installs into a directory the installer created with loose ACLs — a surprisingly common pattern for software that drops into
C:\,C:\Apps\, or a custom folder. - A parent directory in the path grants
Authenticated UsersorUsersaWriteData/AddFilepermission, letting a standard user plant the intercepting binary. - The service is set to
Autostart (or the attacker can restart it), so the payload fires at next boot or on demand.
Chain those together and a non-admin user goes to SYSTEM without a single memory-corruption exploit. It is a configuration flaw, which is exactly why scanners built for CVEs often miss it.
Finding it by hand
On a single machine you can enumerate suspects with WMIC or PowerShell. The classic one-liner filters for paths that contain a space, don't start with a quote, and aren't inside the (relatively safe) Windows directory:
Get-CimInstance Win32_Service |
Where-Object {
$_.PathName -match '^[^"].*\s.*\\' -and
$_.PathName -notmatch '^"' -and
$_.PathName -notmatch '^C:\\Windows'
} |
Select-Object Name, StartMode, StartName, PathName
That gives you the candidates. The second, more important half of the analysis is checking the ACLs on each intermediate directory to see whether a low-privileged principal can actually write there:
icacls "C:\Program Files\Acme Agent"
A path is only genuinely exploitable when an unquoted path and a writable parent directory coexist. Reporting every unquoted path without the ACL check produces a flood of low-signal noise — which is why most manual sweeps get ignored.
How WinSentinel handles it
WinSentinel treats unquoted service paths as a first-class audit check, not a raw registry dump. On any single machine — free, with no limits and all 33 modules active — the service-hardening module enumerates every service, flags unquoted ImagePath values, and crucially correlates each one against the effective ACLs of its parent directories. The finding you see isn't "here are 40 unquoted paths"; it's "these 2 services are actually escalatable because Users can write to an intermediate folder," with the remediation attached.
Remediation is usually a one-line fix — re-register the service with a quoted path:
sc.exe config "AcmeAgent" binPath= "\"C:\Program Files\Acme Agent\bin\service.exe\""
…or tighten the directory ACL so standard users lose write access. WinSentinel surfaces both options and re-checks them on the next audit so you can confirm the fix actually landed.
Scaling the fix across an org
One machine is easy. The problem is that vulnerable services arrive through software deployments, so the same flaw reappears every time a package is pushed to the fleet. This is where WinSentinel Pro earns its place: the central node rolls up unquoted-path findings across every enrolled endpoint, so you can see that (say) 14 of 90 machines share the same vulnerable third-party agent, track remediation as it propagates, and get drift alerts when a new deployment reintroduces the flaw on machines you'd already cleaned. Instead of re-scanning each box by hand, you manage the finding once at the fleet level.
The takeaway
Unquoted service paths are cheap to exploit and cheap to fix — the hard part is knowing which of your dozens of services are genuinely dangerous versus merely cosmetically wrong. Pair the unquoted-path check with an ACL check, remediate the real ones with quotes or tighter permissions, and (if you run more than one machine) watch for the flaw creeping back in through your software pipeline.
A 20-year-old bug survives not because it's hard to fix, but because nobody is looking at the right layer. Audit the ACLs, not just the registry values.