{"id":"CVE-2026-116674","aliases":["CLSA-2026-1793698099","DEBIAN-CVE-2026-116674","EUVD-2026-111104","GHSA-7648-jmwf-vw7j","UBUNTU-CVE-2026-116674"],"status":"published","title":"systeminformation: Prototype pollution in `networkStats()` via the interface name","description":"systeminformation is a System and OS information library for node.js. Prior to 5.33.13, networkStats(ifaces) in lib/network.js on FreeBSD, OpenBSD, and NetBSD stores per-interface data in the plain-object _network cache and indexes it with the sanitized caller-controlled interface name. Passing proto causes the inherited Object.prototype value to be used instead of creating an own cache entry, so calcNetworkSpeed() writes rx_bytes, tx_bytes, rx_sec, tx_sec, ms, last_ms, and operstate onto Object.prototype. The polluted property names are fixed and their values come from interface statistics, but inherited-name collisions and enumerable keys can corrupt application branching, serialization, configuration merging, validation, or lookup behavior. This issue is fixed in version 5.33.13.","severity":{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00287,"percentile":0.21507,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-1321"],"published":"2026-10-27T16:40:46Z","modified":"2026-11-04T02:31:06Z","fixes":[{"ecosystem":"npm","package":"systeminformation","fixed_in":["5.33.13"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"systeminformation","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"5.33.13"}]}]},{"source":"osv","ecosystem":"TuxCare:npm","package":"systeminformation","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"5.23.8-tuxcare.0"},{"fixed":"5.23.8-tuxcare.3"}]}],"versions":["5.23.8","5.23.8-tuxcare.1","5.23.8-tuxcare.2"],"bundled":2},{"source":"osv","ecosystem":"Debian:14","package":"node-systeminformation","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["5.31.6-1","5.31.6-2","5.31.6-3","5.31.6-4","5.31.7-1"]},{"source":"osv","ecosystem":"npm","package":"systeminformation","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"5.33.13"}]}]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"node-systeminformation","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["5.31.6-4","5.31.7-1"]}],"products":[{"vendor":"sebhildebrandt","product":"systeminformation"}],"references":[{"url":"https://github.com/sebhildebrandt/systeminformation/security/advisories/GHSA-7648-jmwf-vw7j","tags":["x_refsource_CONFIRM","exploit","advisory","web","report"]},{"url":"https://github.com/sebhildebrandt/systeminformation/commit/6ff25a1ebc0b1fdc7a8aa3507e46f22007da2969","tags":["x_refsource_MISC","fix","web","report"]},{"url":"https://github.com/sebhildebrandt/systeminformation/releases/tag/v5.33.13","tags":["x_refsource_MISC","web","report"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-116674","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-7648-jmwf-vw7j"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/116xxx/CVE-2026-116674.json","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-116674","tags":["advisory"]},{"url":"https://github.com/sebhildebrandt/systeminformation","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-116674","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-116674","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-116674","title":"systeminformation: Prototype pollution in `networkStats()` via the interface name","description":"systeminformation is a System and OS information library for node.js. Prior to 5.33.13, networkStats(ifaces) in lib/network.js on FreeBSD, OpenBSD, and NetBSD stores per-interface data in the plain-object _network cache and indexes it with the sanitized caller-controlled interface name. Passing proto causes the inherited Object.prototype value to be used instead of creating an own cache entry, so calcNetworkSpeed() writes rx_bytes, tx_bytes, rx_sec, tx_sec, ms, last_ms, and operstate onto Object.prototype. The polluted property names are fixed and their values come from interface statistics, but inherited-name collisions and enumerable keys can corrupt application branching, serialization, configuration merging, validation, or lookup behavior. This issue is fixed in version 5.33.13.","status":"published","published":"2026-10-27T16:40:46.246Z","modified":"2026-11-02T19:30:12.615Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L","level":"medium","assessor":"cna"}],"cwes":["CWE-1321"],"updated_at":"2026-11-02T20:51:24.336573Z"}],"euvd":[{"id":"EUVD-2026-111104","description":"systeminformation is a System and OS information library for node.js. Prior to 5.33.13, networkStats(ifaces) in lib/network.js on FreeBSD, OpenBSD, and NetBSD stores per-interface data in the plain-object _network cache and indexes it with the sanitized caller-controlled interface name. Passing proto causes the inherited Object.prototype value to be used instead of creating an own cache entry, so calcNetworkSpeed() writes rx_bytes, tx_bytes, rx_sec, tx_sec, ms, last_ms, and operstate onto Object.prototype. The polluted property names are fixed and their values come from interface statistics, but inherited-name collisions and enumerable keys can corrupt application branching, serialization, configuration merging, validation, or lookup behavior. This issue is fixed in version 5.33.13.","status":"published","published":"2026-10-27T16:40:46Z","modified":"2026-11-02T19:30:12Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L","level":"medium"}],"updated_at":"2026-11-03T05:08:38.228652Z"}],"ghsa":[{"id":"GHSA-7648-jmwf-vw7j","title":"systeminformation has prototype pollution in `networkStats()` via the interface name","description":"## Summary\n\n`networkStats()` keeps a per interface cache for computing `rx_sec` / `tx_sec` between calls.\nThe cache is a plain JavaScript object and is indexed with the interface name the caller\nsupplied. Passing the name `__proto__` makes every cache write land on `Object.prototype`\ninstead of the cache, polluting every object in the Node.js process.\n\nAn application is affected if it passes untrusted input as the `ifaces` argument of\n`si.networkStats()` and runs on FreeBSD, OpenBSD or NetBSD.\n\n## Details\n\n### The vulnerable code\n\n`lib/network.js` declares the cache as a plain object:\n\n```js\nconst _network = {};\n```\n\n`calcNetworkSpeed()` writes into it, keyed by the interface name:\n\n```js\n} else {\n  if (!_network[iface]) {\n    _network[iface] = {};\n  }\n  _network[iface].rx_bytes  = rx_bytes;\n  _network[iface].tx_bytes  = tx_bytes;\n  _network[iface].rx_sec    = null;\n  _network[iface].tx_sec    = null;\n  _network[iface].ms        = Date.now();\n  _network[iface].last_ms   = 0;\n  _network[iface].operstate = operstate;\n}\n```\n\nWith `iface === '__proto__'` this misbehaves twice:\n\n1. `_network['__proto__']` does not read a missing own property — it invokes the inherited\n   `__proto__` getter and returns `Object.prototype`, which is truthy. The\n   `if (!_network[iface])` guard therefore never creates the `{}` placeholder.\n2. Each following assignment writes onto `Object.prototype`.\n\nAfter one call, `rx_bytes`, `tx_bytes`, `rx_sec`, `tx_sec`, `ms`, `last_ms` and `operstate`\nare visible on **every** object in the process. A second call takes the other branch\n(`_network['__proto__'].ms` is now truthy) and keeps them updated.\n\n### Why the existing sanitizing does not help\n\nThe interface name does pass through `util.sanitizeString(iface, true)` before it is used as\nthe cache key. That function is a **shell metacharacter** filter, built to stop command\ninjection in the `netstat` / `ifconfig` invocations — a different threat. Property names made\nof letters and underscores are legitimate interface names and pass through untouched:\n\n```\n\"a;id\"        -\u003e \"aid\"\n\"a$(id)\"      -\u003e \"aid\"\n\"a|id\"        -\u003e \"aid\"\n\"a`id`\"       -\u003e \"aid\"\n\"__proto__\"   -\u003e \"__proto__\"     \u003c-- unchanged\n\"constructor\" -\u003e \"constructor\"   \u003c-- unchanged\n```\n\nThe sanitizer is doing its job; the gap is that no layer treats the value as an *object key*.\n\n### Reachability\n\nThe cache write is guarded incidentally on three of four platform branches. These guards exist\nfor unrelated reasons and are not a deliberate defence:\n\n| Platform | Code path | Reachable with an arbitrary name? |\n| --- | --- | --- |\n| Linux / Android | `fs.existsSync('/sys/class/net/' + ifaceSanitized)` | **No** — a non-existent interface returns early |\n| macOS | requires `netstat` to emit a data row beyond the header | **No** — verified on macOS 27, `Object.prototype` stays clean |\n| Windows | `if (rx_bytes \u0026\u0026 tx_bytes)` — requires a real adapter match | **No** |\n| **FreeBSD / OpenBSD / NetBSD** | `if (!error) { …; result = calcNetworkSpeed(ifaceSanitized, …) }` | **Yes** — the call sits outside the parsing loop, so any successful `netstat` exit reaches it, and `netstat -ibndI \u003cunknown\u003e` prints only its header and exits `0` |\n\nThe important part is not that three platforms happen to be safe, but that nothing in the\ndesign prevents the write. Any future platform branch without such a guard reopens the issue,\nwhich is why the fix is applied at the cache rather than at the call sites.\n\n### Age\n\nThe pattern predates the v5 line — `git log -S \"_network[iface] = {}\"` traces it back to a\nrefactoring before `v3.42.5`. The v3 and v4 lines are end of life; the advisory covers v5.\n\n## Impact\n\nThe attacker controls which attributes appear on `Object.prototype` but not their values —\nthose come from the interface statistics (`rx_bytes`, `ms`, `operstate` …). The attribute\n*names* are fixed by the library, so this is not an arbitrary-key pollution primitive.\n\nThe consequences are therefore application specific and arise from name collisions:\n\n- Any application code that tests `if (obj.operstate)`, `if (obj.ms)` or similar on an object\n  that should not have those properties now takes the wrong branch.\n- `for…in` loops over plain objects gain seven extra enumerable keys, which can corrupt\n  serialisation, configuration merging or validation logic.\n- Libraries that use `{}` as a lookup map and check membership with `in` or truthiness can\n  return values for keys that were never inserted.\n\nNo path to remote code execution is known, and the values cannot be chosen by the attacker.\n\n## Proof of concept\n\n### The underlying primitive (any platform)\n\n```js\nconst { calcNetworkSpeed } = require('systeminformation/lib/network.js'); // internal\nconst cache = {};                       // the declaration used by the library\ncalcNetworkSpeed('__proto__', 1, 2, 'up', 0, 0, 0, 0);\n\nconsole.log({}.rx_bytes);               // 1\nconsole.log({}.operstate);              // 'up'\nconsole.log(Object.prototype.hasOwnProperty('rx_bytes')); // true\n```\n\n### End to end through the public API (FreeBSD / OpenBSD / NetBSD)\n\n```js\nconst si = require('systeminformation');\n\n(async () =\u003e {\n  console.log('before:', {}.operstate);   // undefined\n  await si.networkStats('__proto__');     // an attacker supplied interface name\n  console.log('after :', {}.operstate);   // 'up'  -\u003e Object.prototype is polluted\n})();\n```\n\nOn Linux, macOS and Windows the same call returns an empty result set and leaves\n`Object.prototype` untouched, for the reasons in the *Reachability* table.\n\n## Patch\n\n`lib/network.js` — give the cache a null prototype, so `__proto__` becomes an ordinary own\nproperty instead of a setter into the prototype chain:\n\n```diff\n-const _network = {};\n+const _network = Object.create(null);\n```\n\nThis is the smallest change that fixes the class of problem rather than one reachable path:\n\n- It is independent of the platform branches, so no guard has to be added or maintained.\n- It keeps behaviour identical for every legitimate interface name — `Object.keys()`,\n  member reads and writes all work unchanged on a null prototype object.\n- It matches the pattern already used elsewhere in the codebase\n  (`lib/filesystem.js:114-115`, `lib/graphics.js:1060`, `lib/graphics.js:1087`).\n- `Object.create` is ES5.1, well below the declared `engines.node \u003e= 10.0.0`.\n\nAfter the patch the hostile name is stored as a normal cache entry:\n\n```js\nconst cache = Object.create(null);\n// ... cache['__proto__'] holds the stats object, Object.prototype is untouched\n```\n\n## Workarounds\n\nFor users who cannot upgrade immediately, either of these is sufficient:\n\n1. **Validate the interface name before calling** — accept only names returned by\n   `si.networkInterfaces()`, or reject the names `__proto__`, `constructor` and `prototype`.\n2. **Never pass untrusted input** as the `ifaces` argument. Passing `'*'` or omitting the\n   argument is unaffected, because those names come from the system rather than the caller.\n\nFreezing `Object.prototype` (`Object.freeze(Object.prototype)`) also prevents the write, but it\nhas wide-reaching side effects on other dependencies and is not recommended as a general\nmitigation.\n\n## Affected versions\n\nAll `5.x` releases up to and including `5.33.12`. Earlier major lines contain the same pattern\nbut are end of life.\n\n### What was verified, and what was not\n\nVerified on this machine (macOS 27, Node 24):\n\n- the pollution primitive, by calling the cache write with `iface = '__proto__'`;\n- that `util.sanitizeString('__proto__', true)` returns the string unchanged, while shell\n  metacharacters are stripped;\n- that unpatched v5 on macOS does **not** pollute through the public API;\n- that `netstat -bdnI \u003cunknown-interface\u003e` prints only its header and exits `0`;\n- that the patch stores the hostile key as an own property and leaves `Object.prototype` clean.\n\nNot verified, because no such host was available:\n\n- end to end exploitation on FreeBSD, OpenBSD or NetBSD. That conclusion is derived from\n  reading the BSD branch of `networkStatsSingle()` — where the `calcNetworkSpeed()` call sits\n  outside the row parsing loop and is reached whenever `netstat` exits successfully — combined\n  with the observed `netstat` exit behaviour above. Worth confirming on a BSD host before\n  publishing, since the affected-platform list depends on it.","status":"published","published":"2026-10-28T21:13:32Z","modified":"2026-10-28T21:13:33Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L","level":"medium"}],"cwes":["CWE-1321"],"updated_at":"2026-11-02T14:41:39.926569Z"}],"nvd":[{"id":"CVE-2026-116674","description":"systeminformation is a System and OS information library for node.js. Prior to 5.33.13, networkStats(ifaces) in lib/network.js on FreeBSD, OpenBSD, and NetBSD stores per-interface data in the plain-object _network cache and indexes it with the sanitized caller-controlled interface name. Passing proto causes the inherited Object.prototype value to be used instead of creating an own cache entry, so calcNetworkSpeed() writes rx_bytes, tx_bytes, rx_sec, tx_sec, ms, last_ms, and operstate onto Object.prototype. The polluted property names are fixed and their values come from interface statistics, but inherited-name collisions and enumerable keys can corrupt application branching, serialization, configuration merging, validation, or lookup behavior. This issue is fixed in version 5.33.13.","status":"published","published":"2026-10-27T17:16:59.453Z","modified":"2026-11-02T20:17:32.51Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L","level":"medium","assessor":"secondary"}],"cwes":["CWE-1321"],"updated_at":"2026-11-03T00:02:37.317866Z"}],"osv":[{"id":"CVE-2026-116674","title":"systeminformation: Prototype pollution in `networkStats()` via the interface name","description":"systeminformation is a System and OS information library for node.js. Prior to 5.33.13, networkStats(ifaces) in lib/network.js on FreeBSD, OpenBSD, and NetBSD stores per-interface data in the plain-object _network cache and indexes it with the sanitized caller-controlled interface name. Passing proto causes the inherited Object.prototype value to be used instead of creating an own cache entry, so calcNetworkSpeed() writes rx_bytes, tx_bytes, rx_sec, tx_sec, ms, last_ms, and operstate onto Object.prototype. The polluted property names are fixed and their values come from interface statistics, but inherited-name collisions and enumerable keys can corrupt application branching, serialization, configuration merging, validation, or lookup behavior. This issue is fixed in version 5.33.13.","status":"published","published":"2026-10-27T16:40:46.246Z","modified":"2026-11-04T02:31:06.954943494Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L","level":"medium"}],"cwes":["CWE-1321"],"updated_at":"2026-11-04T02:54:44.889498Z"},{"id":"DEBIAN-CVE-2026-116674","description":"systeminformation is a System and OS information library for node.js. Prior to 5.33.13, networkStats(ifaces) in lib/network.js on FreeBSD, OpenBSD, and NetBSD stores per-interface data in the plain-object _network cache and indexes it with the sanitized caller-controlled interface name. Passing proto causes the inherited Object.prototype value to be used instead of creating an own cache entry, so calcNetworkSpeed() writes rx_bytes, tx_bytes, rx_sec, tx_sec, ms, last_ms, and operstate onto Object.prototype. The polluted property names are fixed and their values come from interface statistics, but inherited-name collisions and enumerable keys can corrupt application branching, serialization, configuration merging, validation, or lookup behavior. This issue is fixed in version 5.33.13.","status":"published","published":"2026-10-27T17:16:59.453Z","modified":"2026-11-03T09:47:29.659253316Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L","level":"medium"}],"updated_at":"2026-11-03T10:27:58.933618Z"},{"id":"GHSA-7648-jmwf-vw7j","title":"systeminformation has prototype pollution in `networkStats()` via the interface name","description":"## Summary\n\n`networkStats()` keeps a per interface cache for computing `rx_sec` / `tx_sec` between calls.\nThe cache is a plain JavaScript object and is indexed with the interface name the caller\nsupplied. Passing the name `__proto__` makes every cache write land on `Object.prototype`\ninstead of the cache, polluting every object in the Node.js process.\n\nAn application is affected if it passes untrusted input as the `ifaces` argument of\n`si.networkStats()` and runs on FreeBSD, OpenBSD or NetBSD.\n\n## Details\n\n### The vulnerable code\n\n`lib/network.js` declares the cache as a plain object:\n\n```js\nconst _network = {};\n```\n\n`calcNetworkSpeed()` writes into it, keyed by the interface name:\n\n```js\n} else {\n  if (!_network[iface]) {\n    _network[iface] = {};\n  }\n  _network[iface].rx_bytes  = rx_bytes;\n  _network[iface].tx_bytes  = tx_bytes;\n  _network[iface].rx_sec    = null;\n  _network[iface].tx_sec    = null;\n  _network[iface].ms        = Date.now();\n  _network[iface].last_ms   = 0;\n  _network[iface].operstate = operstate;\n}\n```\n\nWith `iface === '__proto__'` this misbehaves twice:\n\n1. `_network['__proto__']` does not read a missing own property — it invokes the inherited\n   `__proto__` getter and returns `Object.prototype`, which is truthy. The\n   `if (!_network[iface])` guard therefore never creates the `{}` placeholder.\n2. Each following assignment writes onto `Object.prototype`.\n\nAfter one call, `rx_bytes`, `tx_bytes`, `rx_sec`, `tx_sec`, `ms`, `last_ms` and `operstate`\nare visible on **every** object in the process. A second call takes the other branch\n(`_network['__proto__'].ms` is now truthy) and keeps them updated.\n\n### Why the existing sanitizing does not help\n\nThe interface name does pass through `util.sanitizeString(iface, true)` before it is used as\nthe cache key. That function is a **shell metacharacter** filter, built to stop command\ninjection in the `netstat` / `ifconfig` invocations — a different threat. Property names made\nof letters and underscores are legitimate interface names and pass through untouched:\n\n```\n\"a;id\"        -\u003e \"aid\"\n\"a$(id)\"      -\u003e \"aid\"\n\"a|id\"        -\u003e \"aid\"\n\"a`id`\"       -\u003e \"aid\"\n\"__proto__\"   -\u003e \"__proto__\"     \u003c-- unchanged\n\"constructor\" -\u003e \"constructor\"   \u003c-- unchanged\n```\n\nThe sanitizer is doing its job; the gap is that no layer treats the value as an *object key*.\n\n### Reachability\n\nThe cache write is guarded incidentally on three of four platform branches. These guards exist\nfor unrelated reasons and are not a deliberate defence:\n\n| Platform | Code path | Reachable with an arbitrary name? |\n| --- | --- | --- |\n| Linux / Android | `fs.existsSync('/sys/class/net/' + ifaceSanitized)` | **No** — a non-existent interface returns early |\n| macOS | requires `netstat` to emit a data row beyond the header | **No** — verified on macOS 27, `Object.prototype` stays clean |\n| Windows | `if (rx_bytes \u0026\u0026 tx_bytes)` — requires a real adapter match | **No** |\n| **FreeBSD / OpenBSD / NetBSD** | `if (!error) { …; result = calcNetworkSpeed(ifaceSanitized, …) }` | **Yes** — the call sits outside the parsing loop, so any successful `netstat` exit reaches it, and `netstat -ibndI \u003cunknown\u003e` prints only its header and exits `0` |\n\nThe important part is not that three platforms happen to be safe, but that nothing in the\ndesign prevents the write. Any future platform branch without such a guard reopens the issue,\nwhich is why the fix is applied at the cache rather than at the call sites.\n\n### Age\n\nThe pattern predates the v5 line — `git log -S \"_network[iface] = {}\"` traces it back to a\nrefactoring before `v3.42.5`. The v3 and v4 lines are end of life; the advisory covers v5.\n\n## Impact\n\nThe attacker controls which attributes appear on `Object.prototype` but not their values —\nthose come from the interface statistics (`rx_bytes`, `ms`, `operstate` …). The attribute\n*names* are fixed by the library, so this is not an arbitrary-key pollution primitive.\n\nThe consequences are therefore application specific and arise from name collisions:\n\n- Any application code that tests `if (obj.operstate)`, `if (obj.ms)` or similar on an object\n  that should not have those properties now takes the wrong branch.\n- `for…in` loops over plain objects gain seven extra enumerable keys, which can corrupt\n  serialisation, configuration merging or validation logic.\n- Libraries that use `{}` as a lookup map and check membership with `in` or truthiness can\n  return values for keys that were never inserted.\n\nNo path to remote code execution is known, and the values cannot be chosen by the attacker.\n\n## Proof of concept\n\n### The underlying primitive (any platform)\n\n```js\nconst { calcNetworkSpeed } = require('systeminformation/lib/network.js'); // internal\nconst cache = {};                       // the declaration used by the library\ncalcNetworkSpeed('__proto__', 1, 2, 'up', 0, 0, 0, 0);\n\nconsole.log({}.rx_bytes);               // 1\nconsole.log({}.operstate);              // 'up'\nconsole.log(Object.prototype.hasOwnProperty('rx_bytes')); // true\n```\n\n### End to end through the public API (FreeBSD / OpenBSD / NetBSD)\n\n```js\nconst si = require('systeminformation');\n\n(async () =\u003e {\n  console.log('before:', {}.operstate);   // undefined\n  await si.networkStats('__proto__');     // an attacker supplied interface name\n  console.log('after :', {}.operstate);   // 'up'  -\u003e Object.prototype is polluted\n})();\n```\n\nOn Linux, macOS and Windows the same call returns an empty result set and leaves\n`Object.prototype` untouched, for the reasons in the *Reachability* table.\n\n## Patch\n\n`lib/network.js` — give the cache a null prototype, so `__proto__` becomes an ordinary own\nproperty instead of a setter into the prototype chain:\n\n```diff\n-const _network = {};\n+const _network = Object.create(null);\n```\n\nThis is the smallest change that fixes the class of problem rather than one reachable path:\n\n- It is independent of the platform branches, so no guard has to be added or maintained.\n- It keeps behaviour identical for every legitimate interface name — `Object.keys()`,\n  member reads and writes all work unchanged on a null prototype object.\n- It matches the pattern already used elsewhere in the codebase\n  (`lib/filesystem.js:114-115`, `lib/graphics.js:1060`, `lib/graphics.js:1087`).\n- `Object.create` is ES5.1, well below the declared `engines.node \u003e= 10.0.0`.\n\nAfter the patch the hostile name is stored as a normal cache entry:\n\n```js\nconst cache = Object.create(null);\n// ... cache['__proto__'] holds the stats object, Object.prototype is untouched\n```\n\n## Workarounds\n\nFor users who cannot upgrade immediately, either of these is sufficient:\n\n1. **Validate the interface name before calling** — accept only names returned by\n   `si.networkInterfaces()`, or reject the names `__proto__`, `constructor` and `prototype`.\n2. **Never pass untrusted input** as the `ifaces` argument. Passing `'*'` or omitting the\n   argument is unaffected, because those names come from the system rather than the caller.\n\nFreezing `Object.prototype` (`Object.freeze(Object.prototype)`) also prevents the write, but it\nhas wide-reaching side effects on other dependencies and is not recommended as a general\nmitigation.\n\n## Affected versions\n\nAll `5.x` releases up to and including `5.33.12`. Earlier major lines contain the same pattern\nbut are end of life.\n\n### What was verified, and what was not\n\nVerified on this machine (macOS 27, Node 24):\n\n- the pollution primitive, by calling the cache write with `iface = '__proto__'`;\n- that `util.sanitizeString('__proto__', true)` returns the string unchanged, while shell\n  metacharacters are stripped;\n- that unpatched v5 on macOS does **not** pollute through the public API;\n- that `netstat -bdnI \u003cunknown-interface\u003e` prints only its header and exits `0`;\n- that the patch stores the hostile key as an own property and leaves `Object.prototype` clean.\n\nNot verified, because no such host was available:\n\n- end to end exploitation on FreeBSD, OpenBSD or NetBSD. That conclusion is derived from\n  reading the BSD branch of `networkStatsSingle()` — where the `calcNetworkSpeed()` call sits\n  outside the row parsing loop and is reached whenever `netstat` exits successfully — combined\n  with the observed `netstat` exit behaviour above. Worth confirming on a BSD host before\n  publishing, since the affected-platform list depends on it.","status":"published","published":"2026-10-28T21:13:32Z","modified":"2026-10-28T21:30:05.739266214Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L","level":"medium"}],"cwes":["CWE-1321"],"updated_at":"2026-11-02T15:46:40.657155Z"},{"id":"UBUNTU-CVE-2026-116674","description":"systeminformation is a System and OS information library for node.js. Prior to 5.33.13, networkStats(ifaces) in lib/network.js on FreeBSD, OpenBSD, and NetBSD stores per-interface data in the plain-object _network cache and indexes it with the sanitized caller-controlled interface name. Passing proto causes the inherited Object.prototype value to be used instead of creating an own cache entry, so calcNetworkSpeed() writes rx_bytes, tx_bytes, rx_sec, tx_sec, ms, last_ms, and operstate onto Object.prototype. The polluted property names are fixed and their values come from interface statistics, but inherited-name collisions and enumerable keys can corrupt application branching, serialization, configuration merging, validation, or lookup behavior. This issue is fixed in version 5.33.13.","status":"published","published":"2026-10-27T17:16:00Z","modified":"2026-10-28T20:17:45.720829018Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L","level":"medium"}],"updated_at":"2026-11-02T16:56:00.081948Z"},{"id":"CLSA-2026-1793698099","title":"TuxCare security update for systeminformation (2 CVEs)","description":"TuxCare rebuilt systeminformation to address 2 CVEs. Fixed in 5.23.8-tuxcare.3.","status":"published","published":"2026-11-03T10:28:20Z","modified":"2026-11-03T13:30:04.022827898Z","updated_at":"2026-11-03T14:04:50.729288Z"}]}}
