Medium CVSS 5.1 firefox Input Validation 🔧 Commit mapped

Overview

Medium
Severity
5.1
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionDue to insufficient escaping of special characters in the "copy as cURL" feature, an attacker could trick a user into using this command, potentially leading to local code execution on the user's system.
ComponentCore
Bug ClassInput Validation
Tracker1949994
Fix commit94a9acebe31f (firefox) +9/-0
CWECWE-77
CVSS vectorCVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
CISA KEVNot listed
CreditedAmeen Basha M K
Disclosed2025-04-29

Background

"Copy as cURL"
A DevTools Network Monitor feature that serializes a captured request into a shell curl command the user can paste into a terminal.
`cmd.exe` escape semantics
In cmd.exe, & is a command separator (a & b runs both). ^ is the escape character, so ^& is a literal ampersand; the pre-patch escaper never neutralized &.
Command injection (CWE-77)
If request data containing & is pasted into cmd.exe, everything after the & is executed as a separate command.

Root Cause Analysis

escapeStringWin neutralized a set of shell-dangerous characters (", \, `, $, %, newlines, non-printables) but omitted the cmd.exe command separator &. Attacker-influenced request fields (URL, headers, POST body) flow into the generated curl string through this escaper, so a value such as foo & calc.exe was emitted with the & intact. When the victim copied the “Copy as cURL” output and ran it in a Windows command prompt, cmd.exe interpreted the unescaped & as a statement separator and executed the trailing text as a second command.

The patch adds one replacement to the escapeStringWin pipeline, .replace(/&/g, "^&"), inserted before the final non-printable escape. This prefixes every & with the cmd.exe escape caret so it is treated as a literal ampersand rather than a command separator. The added test testEscapeStringPosix/Win case confirms that cmd & calc.exe becomes cmd ^& calc.exe, neutralizing the injection. The advisory labels this CWE-77/LogicError; the diff substantiates it concretely as improper neutralization of a shell metacharacter (&) — an input-neutralization/injection defect specific to the Windows shell.

Key insight
The Windows curl escaper forgot that & is a cmd.exe command separator, so attacker-controlled request data carrying & could chain an arbitrary second command into the copied-and-run curl line.

Attack Path

  1. Attacker Induces the victim to make (or inspect) an HTTP request whose data the attacker controls — e.g. a URL, header, or POST body containing ...& calc.exe ... (or a more harmful payload).
  2. Victim Opens DevTools Network Monitor and uses “Copy as cURL” on that request (the social-engineering step; UI:N in the vector reflects it does not require interaction from the attacker’s page, but the user must run the command).
  3. Serialization escapeStringWin emits the attacker’s value with & unescaped.
  4. Paste & run The victim pastes the command into a Windows cmd.exe prompt.
  5. Execution cmd.exe splits on the unescaped & and runs the attacker’s trailing text as a local command — local code execution in the victim’s user context.

Impact Assessment

This is a local-code-execution-via-social-engineering issue, not a direct remote primitive: the attacker gains arbitrary command execution on the victim’s machine only if the victim copies the crafted request’s curl form and runs it in cmd.exe. No browser process memory is corrupted; the “sink” is the user’s shell. Gating is significant (victim must use the feature and paste into a Windows prompt), consistent with the moderate rating, but the outcome when it fires is full local command execution. The POSIX path is unaffected by this specific & gap.

Files Changed

  • devtools/client/netmonitor/test/browser_net_curl-utils.js
  • devtools/client/shared/curl.js

Audit Directions

  • Other `cmd.exe` metacharacters
    Verify the Windows escaper also neutralizes the remaining shell-significant characters (|, <, >, (, ), ^, delayed-expansion !); the follow-up CVE-2025-5264 reworked this escaper further, so cross-check both.
  • Other "copy as" / shell serializers
    Any DevTools or toolchain feature that emits shell-runnable text from captured network data (PowerShell, fetch, wget exporters) should be audited for the same unescaped-separator class.
  • Escaper test coverage
    Ensure the test matrix includes every shell separator for both POSIX and Windows targets, not just the ampersand added here.
diff --git a/devtools/client/shared/curl.js b/devtools/client/shared/curl.js
index 47d2aacfe81..0af5a608cb2 100644
--- a/devtools/client/shared/curl.js
+++ b/devtools/client/shared/curl.js
@@ -424,6 +424,7 @@ const CurlUtils = {
           .replace(/\n/g, "\\n")
           .replace(/\r/g, "\\r")
           .replace(/!/g, "\\041")
+          .replace(/&/g, "^&")
           .replace(/[^\x20-\x7E]/g, escapeCharacter) +
         "'"
       );
diff --git a/devtools/client/netmonitor/test/browser_net_curl-utils.js b/devtools/client/netmonitor/test/browser_net_curl-utils.js
index cdf64ad5f95..17452405eda 100644
--- a/devtools/client/netmonitor/test/browser_net_curl-utils.js
+++ b/devtools/client/netmonitor/test/browser_net_curl-utils.js
@@ -295,6 +295,14 @@ function testEscapeStringPosix() {
     "$'\\xc3\\xa6 \\xc3\\xb8 \\xc3\\xbc \\xc3\\x9f \\xc3\\xb6 \\xc3\\xa9'",
     "Character codes outside of the decimal range 32 - 126 should be escaped."
   );
+
+  // Assert that ampersands are correctly escaped in case its tried to run on Windows
+  const evilCommand = `query=evil\n\ncmd & calc.exe\n\n`;
+  is(
+    CurlUtils.escapeStringPosix(evilCommand),
+    "$'query=evil\\n\\ncmd ^& calc.exe\\n\\n'",
+    "The evil command is escaped properly"
+  );
 }
 
 function testEscapeStringWin() {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/devtools/client/netmonitor/test/browser_net_curl-utils.js b/devtools/client/netmonitor/test/browser_net_curl-utils.js
index cdf64ad5f95..17452405eda 100644
--- a/devtools/client/netmonitor/test/browser_net_curl-utils.js
+++ b/devtools/client/netmonitor/test/browser_net_curl-utils.js
@@ -295,6 +295,14 @@ function testEscapeStringPosix() {
     "$'\\xc3\\xa6 \\xc3\\xb8 \\xc3\\xbc \\xc3\\x9f \\xc3\\xb6 \\xc3\\xa9'",
     "Character codes outside of the decimal range 32 - 126 should be escaped."
   );
+
+  // Assert that ampersands are correctly escaped in case its tried to run on Windows
+  const evilCommand = `query=evil\n\ncmd & calc.exe\n\n`;
+  is(
+    CurlUtils.escapeStringPosix(evilCommand),
+    "$'query=evil\\n\\ncmd ^& calc.exe\\n\\n'",
+    "The evil command is escaped properly"
+  );
 }
 
 function testEscapeStringWin() {
Loading diff…