---
id: CVE-2026-116576
aliases:
  - GHSA-3f7j-7jwc-fxfj
title: >-
  systeminformation vulnerable to Windows command injection in services()
  through Unicode quotation marks
summary: >-
  systeminformation vulnerable to Windows command injection in services()
  through Unicode quotation marks
severity: high
cvss: 7.8
cwe:
  - CWE-78
vendor: systeminformation
product: systeminformation
ecosystem: npm
affected:
  - systeminformation < 5.33.16
patched:
  - systeminformation 5.33.16
published: '2026-10-28'
updated: '2026-10-28'
sourceUpdated: '2026-10-28T22:42:50Z'
source: GHSA
sourceUrl: 'https://github.com/advisories/GHSA-3f7j-7jwc-fxfj'
references:
  - url: >-
      https://github.com/sebhildebrandt/systeminformation/security/advisories/GHSA-3f7j-7jwc-fxfj
  - url: 'https://nvd.nist.gov/vuln/detail/CVE-2026-116576'
  - url: >-
      https://github.com/sebhildebrandt/systeminformation/commit/5014c6d25cfce7363b937977327baa853cdba0bf
  - url: 'https://github.com/sebhildebrandt/systeminformation/releases/tag/v5.33.16'
  - url: 'https://github.com/advisories/GHSA-3f7j-7jwc-fxfj'
tags:
  - ghsa
  - npm
  - cve.org
epss: 0.00145
epssPercentile: 0.03759
ingestedAt: '2026-10-26T20:39:42.618Z'
---

## Overview

### Summary

On Windows, `systeminformation@5.33.15` builds a PowerShell command using the value passed to `services()`. The default sanitizer removes ASCII quotes but keeps Unicode curly quotes, spaces, and parentheses. A crafted service name can use those characters to break out of the generated filter string and run a PowerShell expression. The expression runs with the permissions of the Node.js process.

This report confirms version `5.33.15`. Other package versions have not been checked.

### Details

In `lib/processes.js`, `services()` sanitizes the caller's string with `sanitizeShellString()` and later inserts each resulting name into a `Get-CimInstance Win32_Service -Filter` command. The Windows branch passes that command to `util.powerShell()`.

The sanitizer in `lib/util.js` removes the ASCII double quote, but it does not remove U+201C or U+201D, the left and right curly double quotation marks. It also permits spaces and parentheses when called in its default, non-strict mode. PowerShell accepts the curly marks as string delimiters, so an input can end the filter string and place a command expression in the generated command.

For example, the input below uses curly quotation marks to end the generated filter string and execute `New-Item`. I reproduced this call on Windows against the checked-out `systeminformation@5.33.15` source; it created a marker file with the Node.js process account.

### Proof of concept

Run this on Windows in a disposable directory with Node.js and PowerShell available:

```powershell
mkdir si-command-injection-repro
cd si-command-injection-repro
npm init -y
npm install systeminformation@5.33.15
```

Save the following as `poc.cjs`, then run `node poc.cjs`:

```js
'use strict';

const fs = require('node:fs');
const path = require('node:path');
const si = require('systeminformation');

(async () => {
  const markerName = `si-injection-${process.pid}.txt`;
  const markerPath = path.join(process.cwd(), markerName);
  fs.rmSync(markerPath, { force: true });

  try {
    await si.services(`not-a-service” (New-Item -Name ${markerName} -ItemType File -Force) “`);
    console.log(`markerCreated=${fs.existsSync(markerPath)}`);
  } finally {
    fs.rmSync(markerPath, { force: true });
  }
})().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

Expected output:

```text
markerCreated=true
```

The Windows run returned an array and created the marker (`markerCreated: true`). A benign input left the marker absent. The script removes the marker afterward. I did not identify an application network route that forwards remote input to `services()`, so remote exploitability depends on the consuming application.

### Impact

An application that passes attacker-controlled input to `services()` on Windows can execute PowerShell commands with the Node.js process account's permissions. Depending on that account, commands may read or change accessible files, alter application data, or disrupt the service. I searched this repository for HTTP servers, route handlers, and listener calls and found none. `services()` is exposed through the package API and `getDynamicData()`, so a consuming application could make the input network-reachable if it forwards request data. A separate loopback HTTP harness did trigger the command through a query parameter, but that server was test code and is not part of this repository. The project's `docs/security.html` already warns that arbitrary untrusted input to `services()` needs caution because package sanitization does not cover every case.

## Affected packages

- `systeminformation < 5.33.16`

## Remediation

Upgrade to a patched release:

- `systeminformation 5.33.16`
