CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-116576

CVE-2026-116576: OS Command Injection via Unicode Quotation Marks in Node.js systeminformation

Alon Barad
Alon Barad
Software Engineer

Oct 29, 2026·11 min read·1 visit

Executive Summary (TL;DR)

Prior to version 5.33.16, the systeminformation Node.js package fails to strip Unicode typographic quotation marks in sanitizeShellString() on Windows. Attackers who can pass input to services() or getDynamicData() can use Unicode quotes to break out of a PowerShell Get-CimInstance filter string and execute arbitrary OS commands.

CVE-2026-116576 (GHSA-3f7j-7jwc-fxfj) is an OS Command Injection vulnerability (CWE-78) in the Node.js systeminformation library prior to version 5.33.16 on Microsoft Windows. The services() API function dynamically constructs a PowerShell Get-CimInstance command using caller-supplied service names passed through sanitizeShellString(). While the sanitizer strips standard ASCII quotation marks, it permits Unicode typographic quotation marks (U+2018 through U+201E). Because the Windows PowerShell tokenizer recognizes Unicode quotation marks as valid string literal delimiters, an attacker who controls the service name input can break out of the CIM filter string and execute arbitrary PowerShell commands within the security context of the Node.js process.

Vulnerability Overview

The systeminformation package is a widely deployed Node.js library designed to retrieve hardware, operating system, and process metrics across Linux, macOS, and Windows environments. Because Node.js does not provide native bindings for all operating system queries, systeminformation frequently invokes underlying system utilities and shell interpreters—such as Windows PowerShell, WMI, and standard POSIX binaries—to gather runtime telemetry. When applications expose system monitoring endpoints or administration interfaces, user-supplied parameters are frequently passed into systeminformation functions to filter specific processes, network interfaces, or system services.

In versions prior to 5.33.16, the library contains an OS command injection vulnerability (CWE-78) affecting Microsoft Windows deployments. The flaw resides in the interaction between services() in lib/processes.js and the input sanitization routine sanitizeShellString() in lib/util.js. When querying the state of specific Windows services, services() interpolates caller-supplied service names directly into a PowerShell Get-CimInstance Win32_Service -Filter command string.

Although systeminformation processes caller arguments through sanitizeShellString() to strip shell metacharacters and standard ASCII quotes, the sanitizer fails to account for character encoding equivalencies in the Windows PowerShell parser. Specifically, PowerShell treats typographic Unicode quotation marks (U+2018 through U+201E) as functionally identical to standard ASCII single (') and double (") quotes.

Consequently, an attacker who controls the string passed to services() or the wrapper function getDynamicData() can supply Unicode quotation marks to prematurely terminate the WQL/CIM filter literal. Once outside the quoted context, the attacker can append arbitrary PowerShell expressions that execute with the privileges of the host Node.js runtime.

Root Cause Analysis

The root cause of CVE-2026-116576 is an incomplete denylist in lib/util.js combined with dynamic command string concatenation in lib/processes.js without parameterized execution. When systeminformation.services(srv) executes on Windows (_windows === true), it parses the srv argument into an array of target service names and constructs a PowerShell pipeline using Get-CimInstance.

To prevent command injection across its API surface, systeminformation passes user-supplied arguments through sanitizeShellString(str, strict). This function iterates over characters in the input string and strips known dangerous characters, including ASCII single quotes (' / U+0027), ASCII double quotes (" / U+0022), backticks (` / U+0060), and various shell operators. However, the sanitizer relies on explicit character comparisons against standard ASCII code points.

The Windows PowerShell lexical analyzer (tokenizer) is explicitly engineered to normalize typographic punctuation so that scripts copied from web pages or word processors execute without syntax errors. In the PowerShell tokenizer source (System.Management.Automation.Language.Tokenizer), the following Unicode code points are evaluated as valid string literal delimiters:

  • U+2018 (‘) — Left Single Quotation Mark (treated as ')
  • U+2019 (’) — Right Single Quotation Mark (treated as ')
  • U+201A (‚) — Single Low-9 Quotation Mark (treated as ')
  • U+201B (‛) — Single High-Reversed-9 Quotation Mark (treated as ')
  • U+201C (“) — Left Double Quotation Mark (treated as ")
  • U+201D (”) — Right Double Quotation Mark (treated as ")
  • U+201E („) — Double Low-9 Quotation Mark (treated as ")

Similarly, PowerShell normalizes typographic dashes (U+2013 En Dash –, U+2014 Em Dash —, and U+2015 Horizontal Bar ―) into standard parameter hyphens (- / U+002D).

Because sanitizeShellString() only inspects single-unit UTF-16 code units against ASCII quote characters, characters in the U+2018–U+201E range pass through unmodified. When services() embeds the sanitized output into -Filter "Name='${srv}' or ...", a Unicode double quote (”) or single quote (’) breaks the syntax boundary in PowerShell, transitioning the parser from a string literal context into an executable command or expression context.

Code Analysis

Prior to version 5.33.16, services() in lib/processes.js constructed the Windows service query by concatenating each sanitized service name directly into the wincommand string variable:

// Vulnerable implementation in lib/processes.js (prior to 5.33.16)
if (_windows) {
  let wincommand = 'Get-CimInstance Win32_Service';
  if (srvs[0] !== '*') {
    wincommand += ' -Filter "';
    srvs.forEach((srv) => {
      // srv has only been filtered by sanitizeShellString(), which permits Unicode quotes
      wincommand += `Name='${srv}' or `;
    });
    wincommand = `${wincommand.slice(0, -4)}"`;
  }
  wincommand += ' | select Name,Caption,Started,StartMode,ProcessId | fl';
  util.powerShell(wincommand).then((stdout, error) => {
    // Process output...
  });
}

In lib/util.js, sanitizeShellString() checked individual characters against a static list of ASCII symbols. Because Unicode typographic quotes are represented as single 16-bit code units in JavaScript (s[i].length === 1), they also bypassed the s[i].length > 1 check intended to block surrogate pairs:

// Vulnerable check in sanitizeShellString (lib/util.js prior to 5.33.16)
function sanitizeShellString(str, strict) {
  const s = str || '';
  let result = '';
  for (let i = 0; i <= mathMin(s.length, 2000); i++) {
    if (
      !(
        s[i] === undefined ||
        s[i] === '>' ||
        s[i] === '<' ||
        s[i] === '*' ||
        s[i] === '?' ||
        s[i] === '[' ||
        s[i] === ']' ||
        s[i] === '|' ||
        s[i] === '˚' ||
        s[i] === '$' ||
        s[i] === ';' ||
        s[i] === '&' ||
        s[i] === '(' ||
        s[i] === ')' ||
        s[i] === ']' ||
        s[i] === '#' ||
        s[i] === '\\' ||
        s[i] === '\t' ||
        s[i] === '\n' ||
        s[i] === '\r' ||
        s[i] === "'" ||
        s[i] === '`' ||
        s[i] === '"' ||
        s[i].length > 1 ||
        (strict && s[i] === '(') ||
        (strict && s[i] === ')')
      )
    ) {
      result = result + s[i];
    }
  }
  return result;
}

Note that in services(), sanitizeShellString() is invoked earlier in the function without the strict flag, though parentheses, semicolons, and dollar signs are blocked in non-strict mode depending on the exact version branch. However, even when ;, $, and | are stripped by sanitizeShellString(), breaking out of the double-quoted -Filter "..." string with a Unicode double quote (”, U+201D) allows an attacker to inject additional parameters or pipeline/cmdlet arguments directly into Get-CimInstance or chain commands using whitespace and PowerShell operators that are not blocked.

In commit 5014c6d25cfce7363b937977327baa853cdba0bf, the maintainer implemented a two-layer defense-in-depth fix. First, lib/processes.js was updated to enforce a strict character allowlist (/[^a-zA-Z0-9 _.\-@]/g) on each service name immediately prior to interpolation:

diff --git a/lib/processes.js b/lib/processes.js
index 4758d10..ad741f2 100644
--- a/lib/processes.js
+++ b/lib/processes.js
@@ -377,22 +360,23 @@ function services(srv, callback) {
             if (srvs[0] !== '*') {
               wincommand += ' -Filter "';
               srvs.forEach((srv) => {
-                wincommand += `Name='${srv}' or `;
+                // whitelist: srv is inserted into a PowerShell string
+                wincommand += `Name='${srv.replace(/[^a-zA-Z0-9 _.\-@]/g, '')}' or `;
               });
               wincommand = `${wincommand.slice(0, -4)}"`;
             }
             wincommand += ' | select Name,Caption,Started,StartMode,ProcessId | fl';
             util.powerShell(wincommand).then((stdout, error) => {

Second, sanitizeShellString() in lib/util.js was updated to strip Unicode quotation marks (U+2018–U+201E) and Unicode dashes (U+2013–U+2015):

diff --git a/lib/util.js b/lib/util.js
index 72bc631..1f14ec0 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -749,6 +749,9 @@ function sanitizeShellString(str, strict) {
         s[i] === "'" ||
         s[i] === '`' ||
         s[i] === '"' ||
+        // unicode quotes (U+2018-U+201E) and dashes (U+2013-U+2015) are treated as ' " - by PowerShell
+        (s[i] >= '‘' && s[i] <= '„') ||
+        (s[i] >= '–' && s[i] <= '―') ||
         s[i].length > 1 ||
         (strict && s[i] === '(') ||
         (strict && s[i] === ')') ||

> [!NOTE] > Fix Completeness Assessment: The addition of a strict regular expression allowlist (/[^a-zA-Z0-9 _.\-@]/g) in lib/processes.js completely neutralizes injection vectors within services() regardless of PowerShell parser quirks. However, for other functions relying solely on sanitizeShellString(), the character range check (s[i] >= '‘' && s[i] <= '„') covers U+2018 to U+201E, and (s[i] >= '–' && s[i] <= '―') covers U+2013 to U+2015. While this blocks the standard typographic quote and dash sets in PowerShell 5.1, denylist-based shell sanitization remains inherently fragile compared to parameterized execution or strict allowlisting, especially if other Unicode characters (such as U+FF02 Fullwidth Quotation Mark " or U+FF07 Fullwidth Apostrophe ', or U+00AD Soft Hyphen) are handled specially by downstream command interpreters.

Exploitation

Exploiting CVE-2026-116576 requires a target Node.js application running on Microsoft Windows with systeminformation version < 5.33.16. Because systeminformation is a library and does not expose network sockets by default, an attacker must identify an application entry point—such as an HTTP API parameter, WebSocket message, IPC channel in an Electron application, or CLI argument—that passes attacker-controlled strings into si.services(srv) or si.getDynamicData(srv, ...).

When si.services() processes the input, it splits the input string by comma (,) and sanitizes it. To break out of the Get-CimInstance Win32_Service -Filter "Name='...'" context, the attacker includes Unicode quotation marks such as ” (U+201D) or ’ (U+2019).

Consider the following vulnerable application code:

const express = require('express');
const si = require('systeminformation');
const app = express();
 
app.get('/api/service-status', async (req, res) => {
  const serviceName = req.query.name;
  // User input passed directly to si.services()
  const data = await si.services(serviceName);
  res.json(data);
});
 
app.listen(3000);

When the application invokes si.services(payload) on Windows, util.powerShell() executes the assembled command string via child_process.exec invoking powershell.exe. By injecting ” (U+201D), the attacker closes the -Filter " double-quoted argument early:

const si = require('systeminformation');
 
// Conceptual Proof-of-Concept on Windows (< 5.33.16)
// Using Unicode quotation marks (U+2019 / U+201D) to terminate the -Filter string literal
const payload = "spooler’” ...";
 
si.services(payload).then(data => {
  console.log(data);
});

In the PowerShell tokenizer, the injected Unicode double quote (”) terminates the string argument bound to -Filter. Any subsequent tokens in the payload are parsed as top-level arguments or expressions in the PowerShell pipeline executed under the node.exe process token.

Impact Assessment

CVE-2026-116576 is rated 7.8 (High) under CVSS v3.1 with the vector CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H. The Attack Vector is scored as Local (AV:L) because systeminformation is a local Node.js package that does not inherently listen on a network interface. However, if a consuming web application or microservice forwards remote HTTP request parameters to services() or getDynamicData(), the effective exposure in that specific deployment becomes network-reachable.

Successful exploitation grants the attacker arbitrary PowerShell execution under the Windows security context of the running node.exe process. This results in complete compromise of Confidentiality (C:H), Integrity (I:H), and Availability (A:H) within the scope of the service account running the Node.js application:

  • Confidentiality Impact: The attacker can read application source code, environment variables, configuration secrets, database credentials, and any local files accessible to the Node.js user account.
  • Integrity Impact: The attacker can modify application files, plant persistent backdoors or scheduled tasks, and interact with internal network services accessible from the host.
  • Availability Impact: The attacker can terminate the Node.js process, exhaust system resources, or stop critical Windows services if the Node.js runtime operates with elevated privileges.

Because many system monitoring agents, desktop Electron utilities, and infrastructure management tools utilizing systeminformation run with elevated privileges (such as NT AUTHORITY\SYSTEM or local Administrator) to query privileged OS metrics on Windows, successful command injection frequently leads to full host compromise.

According to FIRST EPSS metrics, the vulnerability currently carries an EPSS score of 0.00145 (0.145%, 3.76th percentile), reflecting that automated mass exploitation is uncommon for library-level vulnerabilities that depend on application-specific routing. CVE-2026-116576 is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog.

Remediation

The primary remediation is to upgrade the systeminformation package to version 5.33.16 or later. Version 5.33.16 incorporates both the strict regular expression allowlist in lib/processes.js and the extended Unicode quote and dash filtering in lib/util.js.

npm install systeminformation@^5.33.16

For environments where dependencies are locked or immediate upgrading is not feasible, developers must enforce strict allowlist validation at the application boundary before passing any external input to systeminformation.services() or systeminformation.getDynamicData():

const SAFE_SERVICE_REGEX = /^[a-zA-Z0-9 _.\-@,]+$/;
 
function queryWindowsServices(userInput) {
  if (typeof userInput !== 'string' || !SAFE_SERVICE_REGEX.test(userInput)) {
    throw new Error('Invalid service name parameter');
  }
  return si.services(userInput);
}

In addition to input validation, operators deploying Node.js applications on Windows should ensure that the node.exe process runs under a dedicated, least-privilege local service account rather than NT AUTHORITY\SYSTEM or an administrative user, unless privileged WMI/CIM access is strictly required.

From a defensive monitoring perspective, security teams should configure Windows Event Logging (PowerShell Script Block Logging, Event ID 4104) and Endpoint Detection and Response (EDR) or Sysmon (Event ID 1 Process Creation) to inspect powershell.exe child processes spawned by node.exe. Alert on command lines containing Get-CimInstance Win32_Service -Filter that include Unicode quotation marks (\u2018–\u201e) or anomalous PowerShell cmdlets.

Official Patches

sebhildebrandtGit commit 5014c6d25cfce7363b937977327baa853cdba0bf implementing allowlist in lib/processes.js and Unicode quote filtering in lib/util.js
sebhildebrandtsysteminformation v5.33.16 release tag
GitHub Security AdvisoryOfficial vendor advisory GHSA-3f7j-7jwc-fxfj

Fix Analysis (1)

Technical Appendix

CVSS Score
7.8/ 10
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
0.14%
Top 96% most exploited

Affected Systems

systeminformation (npm package) < 5.33.16 on Microsoft Windows

Affected Versions Detail

Product
Affected Versions
Fixed Version
systeminformation
sebhildebrandt
< 5.33.165.33.16
AttributeDetail
Vulnerability TypeOS Command Injection (CWE-78)
Affected Componentsysteminformation (services() in lib/processes.js & sanitizeShellString() in lib/util.js)
Target PlatformMicrosoft Windows (Node.js runtime)
CVSS v3.1 Score7.8 HIGH (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
EPSS Score0.145% (3.76th Percentile)
Root CauseIncomplete quote sanitization allowing Unicode smart quotes (U+2018-U+201E) to break out of PowerShell Get-CimInstance filter strings
Patched Version5.33.16
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1059Command and Scripting Interpreter
Execution
T1059.001Command and Scripting Interpreter: PowerShell
Execution
CWE-78
Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The software constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.

Vulnerability Timeline

Patch committed (5014c6d25cfce7363b937977327baa853cdba0bf) and systeminformation v5.33.16 released
2026-10-19
GitHub Security Advisory GHSA-3f7j-7jwc-fxfj and CVE-2026-116576 published to NVD
2026-10-26
EPSS and threat intelligence metrics indexed for CVE-2026-116576
2026-10-28

References & Sources

  • [1]GitHub Security Advisory GHSA-3f7j-7jwc-fxfj
  • [2]NVD - CVE-2026-116576 Detail
  • [3]CVE.org Record - CVE-2026-116576
  • [4]CVEListV5 JSON Record for CVE-2026-116576
  • [5]Fix Commit 5014c6d25cfce7363b937977327baa853cdba0bf - utils() sanitizeShellString extended (windows)
  • [6]systeminformation Release v5.33.16
  • [7]systeminformation GitHub Repository

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•CVE-2026-115923
6.5

CVE-2026-115923: Path Traversal and Catalog Rule Bypass in Backstage Catalog Backend

CVE-2026-115923 (GHSA-w658-mh9p-ww8f) is a path traversal and access control bypass vulnerability in Spotify's Backstage developer portal framework, specifically within the @backstage/plugin-catalog-backend package. Prior to patched versions, DefaultCatalogRulesEnforcer evaluated user-supplied URL catalog locations against configured catalog.rules patterns using raw, uncanonicalized strings. Because downstream URL readers canonicalize URLs and resolve dot segments before fetching resources, an authenticated attacker with location registration permissions can supply percent-encoded traversal sequences (such as %2e%2e) to bypass location restrictions and register untrusted catalog entities.

Amit Schendel
Amit Schendel
3 views•9 min read
•about 3 hours ago•CVE-2026-116695
5.3

CVE-2026-116695: CSS Sanitizer Bypass via Bad URL Tokenization Differential in Crass

An interpretation conflict vulnerability (CWE-436) exists in the Ruby CSS parser library Crass prior to version 1.0.8. When consuming the remnants of a malformed URL token, the tokenizer erroneously checks the previously consumed character to determine if a valid escape sequence is present. Consequently, a closing parenthesis immediately following an escaped backslash sequence is treated as escaped by Crass, while spec-compliant web browsers treat the closing parenthesis as the end of the bad URL token. Downstream CSS sanitizers such as Sanitize, Loofah, and rails-html-sanitizer that rely on Crass to parse and reserialize untrusted CSS can be bypassed to inject arbitrary CSS declarations, style rules, and external @import directives.

Amit Schendel
Amit Schendel
5 views•11 min read
•about 4 hours ago•CVE-2026-116577
5.3

CVE-2026-116577: Algorithmic Complexity Denial of Service in Tornado HTTP Header Parser

Tornado versions prior to 6.6.0 contain an inefficient algorithmic complexity vulnerability in the HTTP header parser. When processing requests with obsolete line folding (obs-fold), the HTTPHeaders.parse_line method repeatedly concatenates immutable Python strings within a list structure. An unauthenticated remote attacker can send an HTTP request containing thousands of short header continuation lines to trigger quadratic O(N^2) CPU consumption on the main IOLoop thread, starving concurrent connections and resulting in a denial of service.

Alon Barad
Alon Barad
7 views•10 min read
•about 5 hours ago•CVE-2026-116578
2.1

CVE-2026-116578: Open Redirect in Tornado RedirectHandler via URL Normalization and Template Substitution

Tornado versions prior to 6.6.0 contain an open redirect vulnerability (CWE-601) in tornado.web.RedirectHandler. When route templates incorporate regular expression capture groups at the start of a path, directly after a fixed host without a trailing slash, or at the beginning of a destination template, unvalidated URL-decoded parameters allow attackers to manipulate the redirect scheme or network location. Because modern browsers normalize URLs according to the WHATWG specification—treating backslashes as forward slashes and stripping control characters—attackers can bypass naive prefix checks and redirect victims to arbitrary external domains.

Alon Barad
Alon Barad
7 views•11 min read
•about 6 hours ago•CVE-2026-115927
5.3

CVE-2026-115927: Event Loop Blocking and Memory Amplification in Tornado Chunked Transfer Encoding Parser

Tornado versions prior to 6.6.0 contain an uncontrolled resource consumption vulnerability (CWE-400) in the HTTP/1.1 chunked transfer encoding parser. When processing incoming chunked payloads that have already buffered in the socket read buffer, Tornado parses chunks in a tight synchronous loop without yielding to the event loop. Furthermore, non-streaming request handlers and SimpleAsyncHTTPClient store each chunk as a discrete Python bytes object inside a list, inducing an approximately 20-fold memory overhead for 1-byte chunks.

Amit Schendel
Amit Schendel
5 views•11 min read
•about 7 hours ago•CVE-2026-117601
9.3

CVE-2026-117601: Improper Cryptographic Signature Verification in Electrum Bitcoin Wallet

A missing cryptographic signature verification vulnerability exists in Electrum Bitcoin Wallet versions prior to 4.8.3. In Electrum's Simplified Payment Verification (SPV) architecture, the client failed to validate input signatures on unconfirmed mempool transactions received from connected Electrum servers. A malicious Electrum server can exploit this flaw by intercepting a legitimate user broadcast, suppressing it, and returning a spoofed unconfirmed transaction with an invalid signature and zero fee that redirects the user's UTXOs to an attacker-controlled address. When the user initiates a Replace-By-Fee (RBF) action to accelerate the seemingly stuck transaction, Electrum signs the spoofed outputs with the user's private keys, resulting in the direct theft of funds.

Amit Schendel
Amit Schendel
9 views•10 min read