← Back to Feed CACHED · 2026-08-29 13:00:47 · CACHE_KEY CVE-2026-15603
CVE-2026-15603 · CWE-117 · Disclosed 2026-08-28

morgan is an HTTP request logger middleware for Node.js.

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

The fix for the front door left the side window open — Unicode line breaks bypass morgan's earlier CR/LF sanitization

CVE-2026-15603 is a bypass of the earlier CVE-2026-5078 fix (morgan 1.11.0) that stripped ASCII CR/LF from log tokens. Researchers discovered that Unicode characters U+0085 (NEL), U+2028 (LINE SEPARATOR), and U+2029 (PARAGRAPH SEPARATOR) survive into log records and cause downstream line-oriented log processors to split a single access-log entry into multiple logical records. This affects all morgan versions below 1.12.0 and applies to every attacker-reachable token: :url, :user-agent, :referrer, :req[header], and :remote-user. Any of the built-in formats (combined, common, default, short) and custom formats using these tokens are vulnerable.

The vendor severity of MEDIUM / 5.3 is accurate and arguably generous. The CVSS vector (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N) correctly captures that this is unauthenticated and network-reachable, but the impact is limited to integrity of log data only — there is no path to code execution, privilege escalation, data exfiltration, or denial of service. Log forging can mislead SIEM correlation, hide attacker tracks, or poison audit trails, but it requires the downstream consumer to be line-oriented (not JSON/structured). In structured logging pipelines (ECS, JSON), the Unicode characters are encoded within field values and the forge fails.

"Log forging via Unicode line separators in morgan — integrity-only, no code exec path"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify morgan-backed endpoint

The attacker identifies a Node.js web application using morgan as its HTTP access logger. This is straightforward — morgan is one of the most popular Express middlewares with ~8–13 million weekly npm downloads. Any HTTP endpoint served by the app will trigger logging.
Conditions required:
  • Target application uses morgan middleware for access logging
  • Target endpoint is network-reachable
Where this breaks in practice:
  • Attacker cannot confirm morgan is in use from outside without source access or error leaks
STEP 02

Craft request with Unicode line separators

The attacker sends an HTTP request containing U+0085, U+2028, or U+2029 in an attacker-controlled field — most easily the User-Agent header, the URL path, or the Authorization: Basic header (for :remote-user). No special tooling is needed; a single curl command with UTF-8 encoded bytes suffices.
Conditions required:
  • Attacker can send arbitrary HTTP requests to the target
Where this breaks in practice:
  • WAFs that normalize or strip non-ASCII control characters in headers will block this
  • Some reverse proxies (nginx, HAProxy) may reject or re-encode URLs containing raw U+2028/U+2029
Detection/coverage: WAF rules matching \u0085, \u2028, \u2029 in request headers can flag this
STEP 03

Morgan writes unsanitized line to log stream

Morgan formats the access log line using the configured format string. Because versions < 1.12.0 only strip ASCII CR/LF (0x0D/0x0A) but not Unicode line terminators, the injected characters pass through to the output stream verbatim, splitting what should be a single log line into multiple records.
Conditions required:
  • Morgan version < 1.12.0
  • Log format includes an attacker-controllable token
Where this breaks in practice:
  • Applications using structured/JSON log transports (winston JSON, pino, Bunyan) encode these characters inside field values — the forge has no effect
  • Applications that pipe morgan output through a sanitizing transform are also immune
STEP 04

Downstream log consumer misparses records

A line-oriented log consumer — such as a SIEM ingestion pipeline configured for Apache Combined Log Format, a grep-based alerting script, or a compliance audit tool — treats the injected Unicode newline as a record boundary. The attacker's forged content becomes a standalone log entry, potentially hiding the real request or injecting false entries that mislead investigation.
Conditions required:
  • Log consumer splits records on Unicode line terminators, not just ASCII newlines
  • Logs are not ingested as structured JSON
Where this breaks in practice:
  • Many modern SIEM pipelines (Splunk HEC, Elastic ECS, Datadog) ingest structured JSON and are immune
  • Splunk's default line-breaking regex (LINE_BREAKER) typically only splits on \r?\n, not Unicode separators — the forge may not even work against Splunk raw-text ingestion
Detection/coverage: SIEM correlation rules looking for access log lines that don't match the expected token count can detect forged entries
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo known exploitation. Not listed on CISA KEV. No reports of active campaigns.
Proof-of-conceptTrivial to reproduce with curl — e.g., curl -H 'User-Agent: legit\xe2\x80\xa8forged 200 OK' https://target/. No dedicated PoC repo published yet; the advisory by UlisesGascon provides sufficient detail.
EPSS scoreNot yet scored (CVE published 2026-08-28, EPSS lags ~48 hours). Expected to be very low (<5th percentile) given integrity-only impact and no code execution.
KEV statusNot listed. No federal mandate to patch on an accelerated timeline.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N — Network-reachable, no auth, no user interaction, but only Low integrity impact. No confidentiality or availability impact.
Affected versionsmorgan < 1.12.0 (all versions including 1.11.x which fixed only ASCII CR/LF via CVE-2026-5078)
Fixed versionmorgan 1.12.0 — now strips U+0085, U+2028, U+2029 in addition to CR/LF
Related CVECVE-2026-5078 — the ASCII CR/LF variant of the same class, fixed in 1.11.0. CVE-2026-15603 is the Unicode bypass of that fix.
Installed basemorgan has ~8–13 million weekly npm downloads. It is a dependency of thousands of Express-based applications. Exposure is broad but impact per-exploit is narrow.
ResearcherUlisesGascon — reported both CVE-2026-5078 and CVE-2026-15603 to the expressjs/morgan project via GitHub Security Advisories.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to MEDIUM (5.3/10)

The single most decisive factor is that the blast radius is limited to log integrity — there is no path from this vulnerability to code execution, privilege escalation, or data breach regardless of the deployment role. Even on a high-value application tier, the worst outcome is polluted audit logs, not host or domain compromise.

HIGH Vulnerability details and affected version range
HIGH Impact ceiling (integrity-only, no code execution)
MEDIUM Downstream SIEM behavior with Unicode line separators (varies by pipeline)
LOW EPSS score (not yet published)

Why this verdict

  • Integrity-only impact ceiling: The CVSS vector confirms C:N/I:L/A:N. No matter how the chain is composed, the terminal impact is log forging — there is no escalation to RCE, privilege gain, or data exfiltration. This hard-caps severity.
  • Role multiplier: morgan runs as an Express middleware in Node.js application servers. In low-value roles (dev, staging), impact is negligible. In typical roles (production web tier), forged logs can mislead SIEM correlation and hide attacker activity — a real but bounded concern. In high-value roles (e.g., Node.js microservices fronting an API gateway for an identity provider), the same log-forging ceiling applies — the attacker gains no additional code execution or identity-plane access. The blast radius is *host log stream* at most, never domain/fleet/supply-chain. The floor does not trigger because no role escalates beyond log integrity impact.
  • Broad installed base, narrow per-exploit impact: ~8–13M weekly downloads means many apps are *reachable*, but the actual damage per exploitation is low. This is a volume × severity trade-off where severity anchors the score.
  • Friction from structured logging: Organizations using JSON/structured log pipelines (pino, winston JSON mode, Elastic ECS) are effectively immune because Unicode characters are encoded within JSON string values and cannot forge new records. This materially reduces the exploitable population.
  • Bypass of prior fix: This is a bypass of CVE-2026-5078's remediation (1.11.0), which means organizations that thought they patched the log-forging class are still vulnerable. This is notable but does not change the impact ceiling.

Why not higher?

The vulnerability cannot escalate beyond log integrity. There is no code execution, no privilege escalation, no data exfiltration, and no availability impact. Even if an attacker forges log entries on a mission-critical system, the host, domain, and fleet remain uncompromised. The CVSS Scope is Unchanged, meaning no cross-component impact. Without a path to a higher-consequence outcome, HIGH or CRITICAL is not warranted.

Why not lower?

The vulnerability is unauthenticated, requires no user interaction, and is trivially exploitable with a single HTTP request against one of the most widely-deployed npm packages. Log integrity is a real security property — forged logs can mask intrusions, poison compliance evidence, and mislead incident response. Downgrading to LOW would understate the operational risk in environments relying on morgan's access logs for security monitoring.

05 · Compensating Control

What to do — in priority order.

  1. Switch to structured/JSON log output — If your application pipes morgan output to a JSON transport (e.g., winston JSON format, pino, or writes to Elastic ECS), Unicode line separators are encoded inside JSON string values and cannot forge new records. This neutralizes the vulnerability entirely. Implement within the 365-day noisgate remediation SLA window while planning the upgrade to 1.12.0.
  2. Upgrade morgan to 1.12.0 — The definitive fix. Run npm update morgan or pin "morgan": "^1.12.0" in package.json. Test in staging first — the only behavioral change is that U+0085/U+2028/U+2029 are now escaped in log output. Deploy within the 365-day noisgate remediation window.
  3. Add WAF rules to strip Unicode control characters from headers — Configure your WAF or reverse proxy to reject or sanitize request headers containing U+0085, U+2028, and U+2029. In nginx, proxy_set_header with a Lua or njs filter can strip these. This is defense-in-depth — it does not fix morgan but prevents the payload from reaching it.
  4. Validate SIEM line-breaking configuration — Audit your SIEM's line-breaking rules for access log sources. Ensure LINE_BREAKER (Splunk) or equivalent only splits on \r?\n, not arbitrary Unicode separators. This limits the downstream impact even if forged bytes reach the log file.
What doesn't work
  • Rate limiting — the attack requires only a single HTTP request to inject a forged log entry. Rate limiting does not help.
  • Input validation on request body — the vulnerable tokens come from HTTP *headers* and the *URL path*, not the request body. Body-focused validation is irrelevant.
  • Upgrading to morgan 1.11.0 — this version only fixed ASCII CR/LF (CVE-2026-5078). Unicode line separators bypass that fix entirely. You need 1.12.0.
06 · Verification

Crowdsourced verification payload.

Run this on each application host or in your CI pipeline to check the installed morgan version. Requires node and npm in PATH. No special privileges needed. Example: bash check_morgan_cve_2026_15603.sh /path/to/your/app

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_morgan_cve_2026_15603.sh
# Checks whether the installed morgan version is vulnerable to CVE-2026-15603
# (Log Forging via Unicode Line Separators)
# Usage: bash check_morgan_cve_2026_15603.sh [/path/to/node/app]
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN

set -euo pipefail

APP_DIR="${1:-.}"

if [ ! -d "$APP_DIR/node_modules/morgan" ]; then
  echo "UNKNOWN — morgan is not installed in $APP_DIR/node_modules"
  exit 2
fi

VERSION=$(node -e "try { console.log(require('$APP_DIR/node_modules/morgan/package.json').version) } catch(e) { console.log('error') }")

if [ "$VERSION" = "error" ]; then
  echo "UNKNOWN — could not read morgan version from $APP_DIR"
  exit 2
fi

echo "Installed morgan version: $VERSION"

# Compare version — vulnerable if < 1.12.0
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3)
MAJOR=$(echo "$VERSION" | cut -d. -f1)

if [ "$MAJOR" -gt 1 ] 2>/dev/null; then
  echo "PATCHED — morgan $VERSION is >= 1.12.0"
  exit 0
elif [ "$MAJOR" -eq 1 ] && [ "$MINOR" -ge 12 ] 2>/dev/null; then
  echo "PATCHED — morgan $VERSION is >= 1.12.0"
  exit 0
else
  echo "VULNERABLE — morgan $VERSION is < 1.12.0 (CVE-2026-15603)"
  exit 1
fi
07 · Bottom Line

If you remember one thing.

TL;DR
This is a MEDIUM log-forging vulnerability with no code execution path — the vendor's 5.3 score is accurate. There is no noisgate mitigation SLA for MEDIUM findings — go straight to the 365-day noisgate remediation SLA. In practice, npm update morgan to 1.12.0 is a one-line change with minimal regression risk; slot it into your next scheduled dependency update cycle. If your Node.js apps already use structured JSON logging (pino, winston JSON, ECS), you are effectively immune and can deprioritize further. If you rely on morgan's raw text output feeding a line-oriented SIEM pipeline, prioritize the upgrade sooner — forged log entries can mask attacker activity during an active incident. Audit your SIEM line-breaking config as a parallel step. No emergency patching is warranted.

Sources

  1. GitHub Advisory — GHSA-jxfw-x594-9x9m (CVE-2026-15603)
  2. GitHub Advisory — GHSA-4vj7-5mj6-jm8m (CVE-2026-5078, prior fix bypass)
  3. GitLab Advisory Database — CVE-2026-5078
  4. CWE-117: Improper Output Neutralization for Logs
  5. expressjs/morgan — GitHub repository
  6. Unicode Line Separator log injection research — lookout.net
  7. DailyCVE — CVE-2026-5078 analysis
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.