GHSA-8h6h-x5pq-56fq: CRLF Injection

Published Aug 26, 2026
·
Updated

@logtape/syslog contains two related output-encoding bugs in the structured data formatting code. Both only affect deployments with includeStructuredData: true, which is non-default.

1. Unescaped C0 control characters in structured data values

escapeStructuredDataValue() in packages/syslog/src/syslog.ts escapes \, ", and ] per RFC 5424 but does not escape newline (\n), carriage return (\r), or any other C0 control characters (U+0000–U+001F):

typescript function escapeStructuredDataValue(value: string): string { return value .replace(/\\/g, "\\\\") .replace(/"/g, '\\"') .replace(/]/g, "\\]"); // \n, \r, and other C0 control characters are not escaped }

TCP syslog commonly uses \n as a frame delimiter (RFC 6587, non-transparent framing). If an attacker-controlled value contains a literal newline, that newline terminates the current syslog frame. Bytes following the newline begin a new frame, and if they form a valid RFC 5424 header (<PRI>1 …), a downstream collector will accept them as a separate, authentic-looking syslog record.

2. Unvalidated SD-NAME keys

Structured data parameter keys are inserted into the message without validation or escaping:

typescript elements.push(${key}="${escapedValue}");

RFC 5424 defines SD-NAME as printable US-ASCII characters excluding =, ], ", and space, with a maximum length of 32. A key containing any of those characters, control characters, or exceeding the length limit will produce malformed structured data. If the key itself contains an embedded ], it can prematurely close the structured-data element.

In typical usage, property keys are developer-defined string literals and therefore safe. However, if an application forwards attacker-controlled keys as log properties—for example by spreading request headers or arbitrary metadata into a log record—this becomes a second injection path.

Proof of concept

The following Node.js snippet (no dependencies, no network required) demonstrates that the escaped value still contains a literal newline:

javascript function escapeStructuredDataValue(value) { return value .replace(/\\/g, "\\\\") .replace(/"/g, '\\"') .replace(/]/g, "\\]"); }

const payload = 'normal\n<134>1 2026-01-01T00:00:00Z forged evil - - - INJECTED';

const result = escapeStructuredDataValue(payload); console.log("Newline present after escape:", result.includes("\n")); // true

Tested with Node.js 22.17.1.

Impact

An attacker who controls log property values can:

- forge syslog records attributed to arbitrary hosts, applications, or process IDs; - insert records with arbitrary severity or facility levels; - obscure malicious activity by injecting misleading entries around legitimate ones; - break downstream log parsers or SIEM correlation rules that rely on log integrity.

Affected downstream collectors include rsyslog, syslog-ng, Splunk, Elastic Stack, and any other system using RFC 6587 non-transparent framing.

Suggested fix

Structured data values

Escape all C0 control characters (U+0000–U+001F) in addition to \, ", and ]. RFC 5424 does not define an escape sequence for control characters in PARAM-VALUE; the most interoperable approach is to strip or replace them:

typescript function escapeStructuredDataValue(value: string): string { return value .replace(/\\/g, "\\\\") .replace(/"/g, '\\"') .replace(/]/g, "\\]") .replace(/[\x00-\x1f]/g, (c) => \\x${c.charCodeAt(0).toString(16).padStart(2, "0")} ); }

Alternatively, strip them entirely: .replace(/[\x00-\x1f]/g, ""). The right choice depends on whether downstream consumers need some representation of the original value.

SD-NAME keys

Validate each key against the RFC 5424 SD-NAME grammar before including it. Keys that fail validation should be skipped or sanitized:

typescript // SD-NAME: printable US-ASCII, excluding '=', ']', '"', SP; max 32 chars const SDNAMERE = /^[!-<>-Z\\^-z|~]{1,32}$/;

for (const [key, value] of Object.entries(record.properties)) { if (!SDNAMERE.test(key)) continue; const escapedValue = escapeStructuredDataValue(String(value)); elements.push(${key}="${escapedValue}"); }

Affected Software

3 affected componentsFixes available
npm/@logtape/syslog<1.3.11
1.3.11
npm/@logtape/syslog>=2.0.0<2.0.14
2.0.14
npm/@logtape/syslog>=2.1.0<=2.1.4
2.1.5

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/@logtape/syslog to a version that resolves this vulnerability.

    Fixed in 1.3.11
  2. Upgrade

    Upgrade npm/@logtape/syslog to a version that resolves this vulnerability.

    Fixed in 2.0.14
  3. Upgrade

    Upgrade npm/@logtape/syslog to a version that resolves this vulnerability.

    Fixed in 2.1.5
  4. Configuration

    Disable structured-data output by setting includeStructuredData: false (it is non-default). This prevents attackers from injecting into RFC 5424 structured data formatting.

    @logtape/syslog includeStructuredData = false
  5. Configuration

    Update escapeStructuredDataValue() in packages/syslog/src/syslog.ts so that it escapes C0 control characters (U+0000–U+001F) in structured-data values. The reported bug escapes `\`, `"`, and `]` but does not escape newline (`\n`), carriage return (`\r`), or other C0 control characters.

    @logtape/syslog structured data formatting / escapeStructuredDataValue() = Escape all C0 control characters (U+0000–U+001F) in addition to `\`, `"`, and `]`
  6. Configuration

    Before including structured-data parameter keys, validate each key against the RFC 5424 SD-NAME grammar (printable US-ASCII excluding `=`, `]`, `"`, and space; max 32 chars). Skip or sanitize keys that fail validation to prevent malformed structured data and injection via unvalidated SD-NAME keys.

    @logtape/syslog SD-NAME validation = Validate and skip/sanitize invalid SD-NAME keys

Event History

Aug 26, 2026
Advisory Published
via GitHub·02:28 PM
Data Sourced
via GitHub·02:28 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Are deployments using the default configuration affected?

No. The issue affects only deployments configured with includeStructuredData: true, which is non-default.

2

What must an attacker control to inject a separate syslog record?

The attacker must be able to place a literal newline in a structured-data value. For frame injection, the deployment must use TCP syslog with non-transparent framing and the bytes after the newline must form a valid RFC 5424 header for a downstream collector to accept them as a separate record.

3

What can be done if an update cannot be applied immediately?

Disable includeStructuredData to avoid the affected structured-data formatting path. Also avoid placing untrusted values or keys into structured data until the deployment is remediated.

4

How can I determine whether my deployment is exposed?

Check whether @logtape/syslog is configured with includeStructuredData: true and whether untrusted input can reach structured-data values or parameter keys. TCP syslog deployments using newline-delimited, non-transparent framing have the specific risk of injected values creating additional frames.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203