CVE-2026-54511: @logtape/syslog Syslog Log Injection Vulnerability

HIGH
Advisory Identifier: GHSA-8h6h-x5pq-56fq
CVSS 8.6
CWE-117 CWE-93
Published
Advisory Summary

CVE-2026-54511 is a HIGH (CVSS 8.6) syslog log injection vulnerability (CWE-117: Improper Output Neutralization for Logs) affecting @logtape/syslog libraries in the npm ecosystem. The issue involves syslog log injection via unescaped control characters and unvalidated sd-name keys. Remediation is available by upgrading affected packages to version 2.1.5, 2.0.14, 1.3.11.

CVE-2026-54511 at a Glance

CVE Identifier CVE-2026-54511
GHSA Identifier GHSA-8h6h-x5pq-56fq
Severity HIGH
CVSS v3.1 Base Score 8.6
CWE Classification CWE-117: Improper Output Neutralization for Logs
Affected Product @logtape/syslog
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 8.6

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality None (C:N)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2026-54511

To remediate this vulnerability, upgrade all affected @logtape/syslog dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

@logtape/syslog fixed: 2.1.5
npm install @logtape/syslog@2.1.5
@logtape/syslog fixed: 2.0.14
npm install @logtape/syslog@2.0.14
@logtape/syslog fixed: 1.3.11
npm install @logtape/syslog@1.3.11
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls @logtape/syslog

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-54511, inspect your project dependencies using npm:

npm ls @logtape/syslog

Analyze the terminal output to locate any version of @logtape/syslog in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.1.5), your application is affected.

Note: The npm ls @logtape/syslog command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-117: Improper Output Neutralization for Logs, where the product constructs a log message from external input, but it does not neutralize or incorrectly neutralizes special elements when the message is written to a log file. In @logtape/syslog, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

`@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 SD_NAME_RE = /^[!-<>-Z\\^-z|~]{1,32}$/; for (const [key, value] of Object.entries(record.properties)) { if (!SD_NAME_RE.test(key)) continue; const escapedValue = escapeStructuredDataValue(String(value)); elements.push(`${key}="${escapedValue}"`); } ```

CVE-2026-54511 Affected @logtape/syslog Versions

3 component(s)
Fixed Versions:
2.1.52.0.141.3.11
Product / Package Ecosystem Affected Versions Fixed Version
@logtape/syslog
npm
≥ 2.1.0
< 2.1.5
2.1.5
@logtape/syslog
npm
≥ 2.0.0
< 2.0.14
2.0.14
@logtape/syslog
npm
< 1.3.11
1.3.11

References

Frequently Asked Questions

What is CVE-2026-54511?
CVE-2026-54511 is a security vulnerability in @logtape/syslog involving syslog log injection via unescaped control characters and unvalidated SD-NAME keys under CWE-117: Improper Output Neutralization for Logs.
Which @logtape/syslog versions are affected?
Affected versions include releases prior to 2.1.5, 2.0.14, 1.3.11 across affected packages: @logtape/syslog.
What version fixes CVE-2026-54511?
Upgrading to 2.1.5, 2.0.14, 1.3.11 (or the latest patched release for your respective branch) resolves the vulnerability.
Is @logtape/syslog affected?
Yes, @logtape/syslog is affected in releases prior to 2.1.5, 2.0.14, 1.3.11. Upgrade your dependency to 2.1.5, 2.0.14, 1.3.11 or later.
What is the CVSS score of CVE-2026-54511?
CVE-2026-54511 has a CVSS v3.1 base score of 8.6 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N.
What CWE is associated with CVE-2026-54511?
CVE-2026-54511 is classified under CWE-117: Improper Output Neutralization for Logs (The product constructs a log message from external input, but it does not neutralize or incorrectly neutralizes special elements when the message is written to a log file.).
How can I check npm dependencies for CVE-2026-54511?
Run the dependency tree command: 'npm ls @logtape/syslog'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-8h6h-x5pq-56fq",
  "modified" : "2026-08-26T14:28:04Z",
  "published" : "2026-08-26T14:28:04Z",
  "aliases" : [ "CVE-2026-54511" ],
  "summary" : "@logtape/syslog: syslog log injection via unescaped control characters and unvalidated SD-NAME keys",
  "details" : "`@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.\n\n## 1. Unescaped C0 control characters in structured data values\n\n`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):\n\n```typescript\nfunction escapeStructuredDataValue(value: string): string {\n  return value\n    .replace(/\\\\/g, \"\\\\\\\\\")\n    .replace(/\"/g, '\\\\\"')\n    .replace(/]/g, \"\\\\]\");\n  // \\n, \\r, and other C0 control characters are not escaped\n}\n```\n\nTCP 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.\n\n## 2. Unvalidated SD-NAME keys\n\nStructured data parameter keys are inserted into the message without validation or escaping:\n\n```typescript\nelements.push(`${key}=\"${escapedValue}\"`);\n```\n\nRFC 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.\n\nIn 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.\n\n## Proof of concept\n\nThe following Node.js snippet (no dependencies, no network required) demonstrates that the escaped value still contains a literal newline:\n\n```javascript\nfunction escapeStructuredDataValue(value) {\n  return value\n    .replace(/\\\\/g, \"\\\\\\\\\")\n    .replace(/\"/g, '\\\\\"')\n    .replace(/]/g, \"\\\\]\");\n}\n\nconst payload =\n  'normal\\n<134>1 2026-01-01T00:00:00Z forged evil - - - INJECTED';\n\nconst result = escapeStructuredDataValue(payload);\nconsole.log(\"Newline present after escape:\", result.includes(\"\\n\")); // true\n```\n\nTested with Node.js 22.17.1.\n\n## Impact\n\nAn attacker who controls log property values can:\n\n- forge syslog records attributed to arbitrary hosts, applications, or process IDs;\n- insert records with arbitrary severity or facility levels;\n- obscure malicious activity by injecting misleading entries around legitimate ones;\n- break downstream log parsers or SIEM correlation rules that rely on log integrity.\n\nAffected downstream collectors include rsyslog, syslog-ng, Splunk, Elastic Stack, and any other system using RFC 6587 non-transparent framing.\n\n## Suggested fix\n\n### Structured data values\n\nEscape 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:\n\n```typescript\nfunction escapeStructuredDataValue(value: string): string {\n  return value\n    .replace(/\\\\/g, \"\\\\\\\\\")\n    .replace(/\"/g, '\\\\\"')\n    .replace(/]/g, \"\\\\]\")\n    .replace(/[\\x00-\\x1f]/g, (c) =>\n      `\\\\x${c.charCodeAt(0).toString(16).padStart(2, \"0\")}`\n    );\n}\n```\n\nAlternatively, strip them entirely: `.replace(/[\\x00-\\x1f]/g, \"\")`. The right choice depends on whether downstream consumers need some representation of the original value.\n\n### SD-NAME keys\n\nValidate each key against the RFC 5424 SD-NAME grammar before including it. Keys that fail validation should be skipped or sanitized:\n\n```typescript\n// SD-NAME: printable US-ASCII, excluding '=', ']', '\"', SP; max 32 chars\nconst SD_NAME_RE = /^[!-<>-Z\\\\^-z|~]{1,32}$/;\n\nfor (const [key, value] of Object.entries(record.properties)) {\n  if (!SD_NAME_RE.test(key)) continue;\n  const escapedValue = escapeStructuredDataValue(String(value));\n  elements.push(`${key}=\"${escapedValue}\"`);\n}\n```",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@logtape/syslog"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "2.1.0"
      }, {
        "fixed" : "2.1.5"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 2.1.4"
    }
  }, {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@logtape/syslog"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "2.0.0"
      }, {
        "fixed" : "2.0.14"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@logtape/syslog"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "1.3.11"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/dahlia/logtape/security/advisories/GHSA-8h6h-x5pq-56fq"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/dahlia/logtape/commit/7a6e5b9ddf7915edfff78fa129bc17c979b2a623"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/dahlia/logtape"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/dahlia/logtape/releases/tag/1.3.11"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/dahlia/logtape/releases/tag/2.0.14"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/dahlia/logtape/releases/tag/2.1.5"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-117", "CWE-93" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-08-26T14:28:04Z",
    "nvd_published_at" : null
  }
}