CVE-2026-116576 — 脆弱性インテリジェンス
— systeminformation
公表日:
- CVSS
- 7.8
- CISA KEV
- 未掲載(悪用がないことを意味しません)
情報源の原文(翻訳ではありません)
systeminformation vulnerable to Windows command injection in services() through Unicode quotation marks
### 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.