Sep 29, 2026·8 min read·25 visits
Unescaped double quotes in morgan log fields allow attackers to forge HTTP status codes and response metrics in access logs, blinding automated SIEM parsers.
CVE-2026-87859 is a medium-severity log injection vulnerability in the Node.js morgan HTTP request logger middleware. Prior to version 1.12.1, the internal sanitization utility fails to escape double-quote characters within logged fields, enabling unauthenticated remote attackers to inject arbitrary text, close log fields early, and spoof critical metadata in downstream log parsers.
The morgan package is an HTTP request logger middleware for Node.js, widely used in Express and Connect-based web applications to generate access logs. Standard access log configurations record critical request attributes, including the client's IP address, HTTP request method, target URI, HTTP status code, and header values such as the Referer and User-Agent. In standard formats like Apache Common and Combined, these text-based header values are encapsulated in double quotes to separate them from other space-delimited positional fields.
This vulnerability, designated as CVE-2026-87859, belongs to the class CWE-117: Improper Output Neutralization for Logs (Log Injection). The logging engine employs an internal function escapeLogField to sanitize user-controlled header values and parameters before they are written to the application log stream. Prior to version 1.12.1, this utility failed to escape double-quote characters, exposing a significant attack surface to unauthenticated remote attackers.
By injecting double quotes into headers such as User-Agent or Referer, an attacker can prematurely close the log field's bounding delimiter. This allows the injection of arbitrary payload strings that appear to downstream log parsers as distinct, system-controlled log fields. This failure in output neutralization exposes applications to log manipulation, masquerading, and potential corruption of automated security information and event management (SIEM) systems.
The following architectural diagram illustrates how the unescaped payload traverses the middleware and corrupts the structural layout of the generated log record:
The root cause of CVE-2026-87859 lies in the incomplete design of the regular expression and replacement logic within the escapeLogField utility function. Introduced in versions 1.11.0 and 1.12.0 to address Carriage Return/Line Feed (CRLF) log injection vectors, the function aimed to neutralize escape and control characters. The underlying assumption was that preventing control characters and line breaks would satisfy log integrity requirements.
The sanitization implementation checked for Unicode characters in specific ranges, backslashes, and standard control codes. The specific regular expression used was /[\u0000-\u001f\u007f-\u009f\u2028\u2029\\]/g. While this regular expression successfully matched and replaced newlines (\n), carriage returns (\r), and backslashes (\\), it completely omitted the double-quote character (").
When morgan processes an HTTP request, it evaluates the format string defined by the developer. In standard formats, tokens like :user-agent and :referrer are hardcoded with enclosing double quotes, such as ":user-agent". When a request contains a header with an unescaped double quote, escapeLogField returns the string unmodified because the character does not match the regular expression. The resulting log entry contains an uneven or misplaced number of double quotes, splitting a single logical field into multiple space-separated elements.
This structural break exploits the basic parser assumption that the content inside the delimiters does not contain raw delimiters. Downstream analysis tools process logs sequentially, using spaces as field separators unless they are within double-quote boundaries. By inserting a double quote, the attacker manipulates the parser's state machine, shifting the index of all subsequent positional values and causing the parser to interpret malicious input as legitimate metadata.
To understand the implementation flaw, we examine the vulnerable version of the escapeLogField function in index.js. The vulnerable code fails to recognize or escape double quotes, passing them directly to the active write stream.
// Vulnerable Implementation (morgan < 1.12.1)
function escapeLogField (value) {
if (value == null) return undefined
// eslint-disable-next-line no-control-regex
return String(value).replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029\\]/g, function (ch) {
switch (ch) {
case '\\': return '\\\\'
case '\b': return '\\b'
case '\f': return '\\f'
case '\n': return '\\n'
case '\r': return '\\r'
case '\t': return '\\t'
}
var hex = ch.charCodeAt(0).toString(16)
return '\\u0000'.slice(0, 6 - hex.length) + hex
})
}The vulnerability is resolved in version 1.12.1 via commit 4b695edf967ce179cdf4009fe8cddd184b7511ee. The patch updates the regular expression to explicitly capture double quotes and maps them to an escaped literal replacement inside the switch block:
// Patched Implementation (morgan >= 1.12.1)
function escapeLogField (value) {
if (value == null) return undefined
// eslint-disable-next-line no-control-regex
// Added double quote character to the regular expression character class
return String(value).replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029"\\]/g, function (ch) {
switch (ch) {
case '\\': return '\\\\'
case '"': return '\\"' // Added explicit escaping mapping for double quote
case '\b': return '\\b'
case '\f': return '\\f'
case '\n': return '\\n'
case '\r': return '\\r'
case '\t': return '\\t'
}
var hex = ch.charCodeAt(0).toString(16)
return '\\u0000'.slice(0, 6 - hex.length) + hex
})
}An evaluation of this patch shows that it is robust against common bypass techniques. Because backslashes (\\) and double quotes (") are handled within the same global replace execution path, an attacker cannot supply a pre-escaped sequence like \" to bypass the filter. The regular expression matches the backslash and the double quote independently, converting the input \" into \\\". This prevents escape-character smuggling and ensures that any quote written to the final log stream is preceded by an odd number of escape characters, rendering it inert to downstream parsers.
Exploiting this vulnerability requires zero administrative privileges and can be achieved through a standard HTTP request. The target application must be configured to log user-controlled headers (such as User-Agent or Referer) using a format that wraps these tokens in double quotes. This configuration is the default in the standard Apache Combined format utilized by many production servers.
To demonstrate, an attacker can transmit an HTTP GET request with a manipulated User-Agent header containing a payload designed to inject fake downstream fields. Consider the following HTTP request structure:
GET /admin/bruteforce HTTP/1.1
Host: vulnerable-target.internal
User-Agent: Mozilla/5.0" 200 8430 "-" "LegitimateAgentWhen processed by a vulnerable version of morgan configured with the Apache Combined format, the generated log entry is written as:
10.0.0.5 - - [11/Sep/2026:09:12:00 +0000] "GET /admin/bruteforce HTTP/1.1" 401 243 "-" "Mozilla/5.0" 200 8430 "-" "LegitimateAgent"Under normal circumstances, the actual server-side response was a 401 Unauthorized with a size of 243 bytes. However, when a downstream parser evaluates the generated log, it scans the line sequentially. It identifies "Mozilla/5.0" as the complete User-Agent string. The parser then processes the adjacent unquoted values, interpreting 200 as the HTTP status code and 8430 as the response body size. This masks the failed authorization attempt and generates a false record of successful communication in automated monitoring reports.
The security impact of CVE-2026-87859 is categorized as medium (CVSS 5.3), with low integrity impact and zero direct confidentiality or availability consequences. However, this assessment does not fully reflect the operational risk in enterprise environments. Log data serves as the primary source of truth for forensic analysis, intrusion detection, and compliance auditing. When log integrity is compromised, the reliability of the entire security monitoring infrastructure is undermined.
An attacker can exploit this flaw to execute defense evasion. By spoofing status codes and request paths, an attacker can make unauthorized API access or brute-force attempts appear as successful, benign transactions. This can prevent security operations centers (SOC) and automated security alerts from triggering on indicators of compromise (IoCs). Furthermore, this can mislead incident response teams during post-exploitation investigations, directing focus away from the compromised assets.
Additionally, log injection poses a threat to downstream data pipelines. Parsers built on regular expressions or rigid delimiter rules can experience processing failures when encountering unexpected field structures. If the ingestion pipeline is configured to drop malformed lines, an attacker can intentionally inject malformed sequences to delete log traces of their activity. Alternatively, in complex setups, injecting unexpected fields can cause buffer overflows, high CPU usage, or crash downstream processing agents like Logstash or Fluentd.
The primary remediation path is upgrading the morgan dependency to version 1.12.1 or later. This can be accomplished by running npm install morgan@1.12.1 or updating the package definition in package.json and running npm update. Security teams should execute dependency scanning tools to identify nested installations of vulnerable versions within their application dependency trees.
If upgrading is not immediately feasible due to legacy system constraints, temporary mitigation can be implemented. Developers can define custom log formats that do not rely on double quotes to encapsulate user-controlled tokens. For example, replacing standard quote delimiters with alternative, non-user-supplied structural formats can mitigate the risk of field breakouts. Alternatively, implementing a custom sanitization wrapper around tokens before passing them to the log format can serve as an effective stopgap.
To detect past exploitation attempts, security engineers should inspect historical logs for anomalies. Specifically, look for log lines containing an odd number of double quotes, which indicates an unescaped character has broken the structural framing. In addition, search for common HTTP statuses or file sizes immediately following what should be the terminating quote of the User-Agent or Referer fields. This search can be automated within SIEM tools using custom pattern matches.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
morgan Expressjs / OpenJS Foundation | < 1.12.1 | 1.12.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-117 (Improper Output Neutralization for Logs) |
| Attack Vector | Network (Unauthenticated) |
| CVSS Score | 5.3 (Medium) |
| EPSS Score | 0.00393 (Percentile: 33.29%) |
| Impact | Low Integrity (Log Spoofing & Manipulation) |
| Exploit Status | PoC Available |
| KEV Status | Not Listed |
The software does not neutralize or incorrectly neutralizes output written to logs, allowing unsanitized input to modify log entries or forge log entries.
An information exposure vulnerability in Ruby on Rails Action Pack allows sensitive session cookies to be attached to public, cacheable responses served by Active Storage proxy controllers. When cookie secret rotation or a hybrid cookie serializer migration is enabled, reading a legacy-format cookie triggers an automatic cookie rewrite that ignores the session-skipping directive. If an intermediate shared cache or CDN caches the resulting response along with its Set-Cookie header, subsequent users requesting the same URL receive the leaked session token.
CVE-2026-126072 (GHSA-rwvh-fw6r-pwvp) is a concurrency deadlock vulnerability in the Ruby on Rails Action Pack framework affecting applications that utilize ActionController::Live response streaming. The defect occurs due to improper synchronization within ActionController::Live::Buffer when handling full bounded queues during stream closure and connection abortion. An unauthenticated remote attacker can trigger this condition by stalling TCP socket reads on streaming endpoints—including Active Storage proxy mode—resulting in permanent worker thread exhaustion and application-wide denial of service.
CVE-2026-126192 is an algorithmic complexity vulnerability in Soup Sieve (soupsieve), the default CSS selector engine for Beautiful Soup 4 in Python. Evaluating a CSS selector that contains a general sibling combinator (~) nested inside a :has() relational pseudo-class against attacker-controlled HTML markup triggers O(n^2) quadratic evaluation complexity when the right-hand sibling target is absent. An unauthenticated attacker can supply small HTML documents containing thousands of sibling elements to exhaust CPU resources and stall application worker threads.
CVE-2026-126190 (GHSA-mmhr-3c5m-f64f) is an inefficient algorithmic complexity vulnerability (CWE-407) in Soup Sieve, the default CSS selector library integrated into Beautiful Soup 4. In versions prior to 4.0, evaluating CSS selectors that contain descendant combinators (whitespace between compound selectors) executes an unmemoized upward traversal of the document tree. When evaluated against deeply nested HTML or XML documents, the time complexity scales polynomially at O(n^(k+1)), where n is the tree depth and k is the number of descendant combinators. Remote attackers can supply compact, deeply nested markup (1 KB to 4 KB) to trigger prolonged CPU starvation and denial of service in Python applications.
CVE-2026-122006 is a critical vulnerability in the Ruby on Rails Active Storage framework affecting versions prior to 8.0.5.2 and 8.1.4.1. When an application processes uploaded file attachments using the ImageMagick variant processor (:mini_magick), the framework invokes ImageMagick's metadata analyzer without applying a restrictive security policy. An unauthenticated attacker can upload a crafted file containing directives for unrestricted ImageMagick coders, such as Magick Scripting Language (MSL), resulting in arbitrary server-side file read and write operations. In deployments using the Disk storage service, attackers can exfiltrate sensitive application configuration files, including secret_key_base and master encryption keys, which enables remote code execution via signed payload forgery.
CVE-2026-128065 (also tracked as GHSA-gg5j-6742-v827) is an authorization bypass vulnerability affecting the @grpc/grpc-js-xds library in the Node.js gRPC ecosystem. In versions 1.14.0 and 1.14.1, XdsServer acknowledges Route and VirtualHost resources from an xDS control plane while failing to parse, store, or apply RBACPerRoute override configurations. When experimental RBAC is enabled and a broad top-level ALLOW policy is paired with restrictive VirtualHost or Route overrides, the server evaluates requests strictly against the top-level policy, permitting unauthorized RPC execution.