CVE-2026-24739

The Equalizer: How a Single Character Deleted Your Drive

Alon Barad
Alon Barad
Software Engineer

Jan 28, 2026·6 min read·8 visits

Executive Summary (TL;DR)

Symfony forgot to quote the '=' character on Windows. If you run PHP scripts in Git Bash and use Symfony Process to handle paths with '=', MSYS2 mangles the path. In the worst case, a command meant to delete a sub-folder deletes your entire drive instead.

A critical argument injection vulnerability in the Symfony Process component allows for destructive file operations when running on Windows under MSYS2/Git Bash environments. Due to improper escaping of the equals sign (=), the MSYS2 'Magic Path Conversion' layer misinterprets file paths, potentially truncating arguments and causing commands like 'rmdir' to execute on parent directories or drive roots.

The Hook: Command Lines are Fake News

If you've spent any time in the trenches of Windows development, you know the uncomfortable truth: argv[] is a lie. Unlike Unix systems, where the kernel gratefully accepts an array of strings, Windows CreateProcess takes a single, massive string. It is then up to the child process (or the runtime invoking it) to parse that string back into arguments. It’s a game of telephone played by drunk operating systems.

Enter MSYS2 (the engine behind Git Bash), which tries to be the helpful translator between the POSIX world developers love and the Windows reality they inhabit. MSYS2 employs something called "Magic Path Conversion." It attempts to spot POSIX-style paths (like /c/users) and convert them to Windows paths (C:\Users) on the fly. Usually, this is great. But like an overly eager autocorrect, it sometimes makes catastrophic assumptions.

CVE-2026-24739 is what happens when that game of telephone goes horribly wrong. Symfony, the bedrock of modern PHP, failed to realize that the equals sign (=) is a trigger for MSYS2's magic logic. The result? A vulnerability that turns a mundane cleanup script into a digital woodchipper for your hard drive.

The Flaw: A Regex Missing its Teeth

The vulnerability hides in Symfony\Component\Process\Process.php. This component is responsible for taking your nice, clean array of arguments and stitching them into that single command line string Windows demands. To do this safely, it needs to escape or quote characters that the shell might misinterpret. Symfony had a blacklist of dangerous characters: spaces, pipes, carets, redirects, and quotes. If an argument contained any of these, Symfony would wrap it in double quotes.

Here is where the logic failed: the developers missed the = character. Why does this matter? On standard cmd.exe, = is harmless. But in the MSYS2 ecosystem, = is a delimiter. It’s used for things like prefix=/usr/bin. When MSYS2 sees an unquoted argument with an equals sign, it thinks, "Aha! A configuration flag! Let me translate the path after the equals sign."

Because Symfony didn't quote arguments containing =, it passed them raw to the shell. If you had a path like E:/=projects/my_app, MSYS2 didn't see a file path; it saw a key-value pair. Its heuristic path translation kicked in, panicked, and in certain scenarios, mangled the path entirely. This isn't just a "bug"; it's an architectural collision between PHP's escaping logic and MSYS2's translation layer.

The Code: The Smoking Gun

Let's look at the diff. It’s painfully simple, which is usually the hallmark of the most dangerous bugs. The escapeArgument method relied on a regex to decide when to quote a string.

The Vulnerable Code:

// src/Symfony/Component/Process/Process.php
 
if (!preg_match('/[()%!^"<>&|\s]/', $argument)) {
    return $argument;
}

If your argument was C:\Temp\=DeleteMe, the regex looks at it, sees no spaces, no pipes, no quotes, and says "Safe!" It returns the raw string.

The Fix (Commit ec154f6f):

// src/Symfony/Component/Process/Process.php
 
// Look at the regex character class expansion
if (!preg_match('/[()%!^"<>&|\s[\]=;*?\'\$]/', $argument)) {
    return $argument;
}

The fix doesn't just add =. The maintainers realized their blacklist was woefully incomplete for the chaotic world of Windows shells. They added square brackets [], semicolons ;, wildcards *?, single quotes ', and the dollar sign $.

By adding =, Symfony now wraps C:\Temp\=DeleteMe into "C:\Temp\=DeleteMe". When MSYS2 sees the double quotes, it backs off. It treats the string as a literal, disabling the magic path conversion that causes the corruption.

The Exploit: Deleting the Universe

Here is the nightmare scenario. You are a developer using a CLI tool built on Symfony (like Composer or a deployment script). You are working on a Windows machine using Git Bash because you prefer the syntax.

The tool needs to clean up a directory. It runs something like this:

$process = new Process(['rmdir', '/S', '/Q', 'E:/repos/=temporary_build']);
$process->run();

In a sane world, this deletes the =temporary_build folder. But here is what actually happens in the pipeline:

  1. Symfony Construction: The regex misses the =. The command string becomes: rmdir /S /Q E:/repos/=temporary_build.
  2. MSYS2 Interception: Git Bash receives this. It parses the arguments. It sees E:/repos/=temporary_build unquoted.
  3. The Mangle: MSYS2's path conversion logic triggers. Depending on the exact version and environment, it may split the string at = or attempt to resolve the path relative to the MSYS2 root. In documented cases, this conversion can truncate the path to the nearest recognized mount point or parent.
  4. Execution: The command effectively becomes rmdir /S /Q E:/.

rmdir is obedient. It doesn't ask questions. It starts recursively deleting everything on your E: drive. This isn't theoretical; this is a known side effect of argument parsing misalignment on Windows. The "Attack Complexity" is listed as High only because it requires specific path naming, but "High Complexity" is little comfort when your backup drive is being wiped.

The Impact: Why You Should Care

The impact here is Integrity and Availability at their peak. We aren't talking about stealing a session cookie; we are talking about data destruction.

Consider CI/CD pipelines. Many runners execute on Windows but use Bash shells for script compatibility. If an attacker can control a directory name (e.g., via a Pull Request creating a file in a specifically named path), they could trigger a cleanup script that wipes the runner's workspace or even system directories if permissions allow.

The specific vector—MSYS2 path conversion—is insidious because it happens outside the application's logic. You can validate inputs all day in PHP, but once that string leaves the PHP process and enters the shell layer, the rules change. This vulnerability serves as a grim reminder: relying on blacklists for escaping is a game of whack-a-mole you will eventually lose.

The Fix: Quoting the Unquotable

The immediate remediation is to update Symfony. The patches (5.4.51, 6.4.33, 7.3.11, etc.) force quoting for a much broader range of characters.

However, the deeper lesson here is about environment hygiene. If you are running critical, destructive operations on Windows, stop using Git Bash wrappers for them. Use cmd.exe or PowerShell directly where possible, as they don't perform this "magic" translation layer that tries to outsmart the user.

If you absolutely must use MSYS2/Git Bash, you can set the environment variable MSYS2_ARG_CONV_EXCL to exclude specific arguments from conversion, though this is a fragile band-aid compared to patching the framework itself. If you are a library maintainer, stop blacklisting characters. Whitelist them. If it's not alphanumeric, quote it. Paranoia is a virtue.

Fix Analysis (1)

Technical Appendix

CVSS Score
6.3/ 10
CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:H

Affected Systems

Symfony Framework < 5.4.51Symfony Framework 6.4.x < 6.4.33Symfony Framework 7.3.x < 7.3.11Symfony Framework 7.4.x < 7.4.5Composer (running on Windows via Git Bash)PHP Applications using Symfony Process on Windows

Affected Versions Detail

Product
Affected Versions
Fixed Version
Symfony
Symfony
< 5.4.515.4.51
Symfony
Symfony
>= 6.4.0, < 6.4.336.4.33
Symfony
Symfony
>= 7.3.0, < 7.3.117.3.11
Symfony
Symfony
>= 7.4.0, < 7.4.57.4.5
Symfony
Symfony
>= 8.0.0, < 8.0.58.0.5
AttributeDetail
CWE IDCWE-88
CVSS v3.16.3 (Medium)
Attack VectorLocal (Context Dependent)
ImpactHigh Integrity / High Availability
PlatformWindows (MSYS2/Git Bash)
Bug ClassArgument Injection / Improper Escaping
CWE-88
Argument Injection

Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')

Vulnerability Timeline

Issue reported via GitHub
2026-01-02
Fix committed to Symfony repo
2026-01-23
CVE Published and Patched Versions Released
2026-01-28

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.