Safeguard
Vulnerability Analysis

systeminformation npm package command injection (CVE-2021-21315)

A critical command injection flaw in the systeminformation npm package (CVE-2021-21315) let attackers run OS commands via unsanitized shell calls. Here's the full breakdown.

Nayan Dey
Security Researcher
8 min read

In February 2021, security researchers disclosed a critical command injection vulnerability in systeminformation, a widely used npm package that provides cross-platform access to hardware, OS, and process-level system data. Tracked as CVE-2021-21315, the flaw allowed an attacker who could influence specific input values to execute arbitrary operating system commands with the privileges of the running Node.js process. Because systeminformation is pulled in — often as a transitive dependency — by monitoring dashboards, server management tools, Electron desktop apps, and CLI utilities, the practical blast radius extended well beyond developers who installed the package directly.

This post breaks down what the vulnerability was, who was affected, how it was disclosed and fixed, and what remediation looks like for teams that still have exposed versions sitting in their dependency trees.

What is systeminformation?

systeminformation is a zero-dependency npm library that queries the underlying operating system — Windows, Linux, macOS, and various Unix variants — to return structured data about CPU, memory, disks, network interfaces, running processes, services, battery status, Docker containers, and more. It ships as both a promise-based and callback-based API and is popular in Node.js server monitoring stacks, PM2-style process managers, Homebridge/IoT dashboards, and internal admin tooling where a quick snapshot of host health is useful.

To gather some of this data on certain platforms, the library shells out to native OS commands (e.g., wmic, systemctl, lsblk, sc query) rather than relying solely on Node's built-in OS APIs, since some of the requested detail simply isn't exposed through standard runtime bindings. That design choice — invoking a shell with dynamically constructed command strings — is exactly where the vulnerability originated.

The Vulnerability

CVE-2021-21315 is classified as a command injection (CWE-78) issue. According to the public advisory (GHSA-motw-wvvj-qc63) and the disclosure published by security research firm Sonar, several internal functions in systeminformation built shell command strings via direct concatenation of data — including, in some code paths, values that could be influenced by an attacker or by untrusted system state — before passing the resulting string to child_process.exec(). Because exec() invokes a full shell (/bin/sh or cmd.exe) rather than executing a binary directly with an argument array, any unescaped shell metacharacters (;, |, `, $(), &&) embedded in that string are interpreted by the shell rather than treated as literal data.

The disclosure was part of a broader batch of related findings in the same package (several sibling CVEs were assigned to systeminformation around the same time for similar root causes across different functions), underscoring that the string-concatenation-into-exec() pattern was systemic in the codebase rather than a single isolated oversight. The specific advisory tied to CVE-2021-21315 centers on service- and process-enumeration code paths where a parameter used to filter results was not sanitized before being folded into the shell command executed to retrieve that data.

The net effect: in applications that exposed any user-controllable path into these systeminformation calls — for example, an admin dashboard that lets a user filter services or processes by name, or an API endpoint that passes query parameters through to the library — an attacker could inject shell syntax and have the underlying OS execute arbitrary commands.

CVSS and risk context:

  • CVSS v3.1 Base Score: 9.8 (Critical) — reflecting network attack vector, low attack complexity, no privileges required, no user interaction, and high impact to confidentiality, integrity, and availability once triggered.
  • EPSS: Historically low-to-moderate exploit prediction probability for this specific CVE, consistent with a library-level flaw that requires an application to expose the vulnerable code path with attacker-controlled input rather than being remotely triggerable on its own.
  • CISA KEV: Not listed in the Known Exploited Vulnerabilities catalog as of this writing. That does not mean it is safe to ignore — plenty of unlisted, "library-only" CVEs have gone on to be chained into real intrusions once an application happens to expose the vulnerable function to untrusted input.

The severity score is a worst-case ceiling: whether it's actually exploitable in your environment depends entirely on whether your code — or a transitive dependency's code — calls the affected function with data an attacker can shape. That distinction is exactly why reachability matters more than CVSS score alone, a point we return to below.

Affected Versions and Components

  • Package: systeminformation (npm)
  • Affected versions: All versions prior to 5.3.1
  • Fixed version: 5.3.1 and later
  • Ecosystem: Node.js / npm, cross-platform (Windows, Linux, macOS)
  • Exposure pattern: Both direct dependents and, notably, indirect consumers — many teams had systeminformation several layers deep in their dependency graph via monitoring middleware, admin panel templates, or IoT/home-automation integrations, without realizing it was present at all.

Because npm's flexible version ranges (^, ~) mean a project's package-lock.json or yarn.lock can silently resolve to a vulnerable minor version even when package.json looks reasonable, simply reading package.json is not sufficient to confirm exposure — the lockfile (or an SBOM) has to be checked against the actual resolved version.

Timeline

  • Pre-2021: The vulnerable command-construction pattern exists across multiple systeminformation internal functions for an extended period, shipped as part of normal feature development for OS-level data collection.
  • Early 2021: Security researchers (Sonar's security research team) identify and responsibly disclose a set of command injection issues in the package, including the one later assigned CVE-2021-21315.
  • February 2021: The maintainer ships a fix in systeminformation 5.3.1, replacing unsafe string-concatenated exec() calls with sanitized input handling and safer command execution patterns.
  • February 2021: CVE-2021-21315 and the corresponding GitHub Security Advisory (GHSA-motw-wvvj-qc63) are published, along with sibling advisories covering related injection points fixed in the same release.
  • Ongoing: Because the package is often a transitive dependency, vulnerable versions continued to surface in dependency scans for months (in some cases years) afterward, in projects that never directly upgraded or re-resolved their lockfiles.

Remediation Steps

  1. Upgrade immediately. Update systeminformation to 5.3.1 or later (the current release is safer still — always track the latest stable version for a zero-dependency package like this one). Run npm ls systeminformation or yarn why systeminformation to identify every place it resolves in your dependency tree, since it is frequently transitive.

  2. Regenerate lockfiles, don't just bump package.json. If systeminformation is a transitive dependency of another package, bumping your direct dependency's version may not be enough — you may need npm update, a resolutions/overrides entry (overrides in npm, resolutions in Yarn), or an upstream fix from the intermediate package before the vulnerable version actually disappears from your lockfile.

  3. Audit call sites for attacker-controlled input. Search your codebase for any place where a systeminformation function result or parameter is influenced by request data, query strings, form fields, or configuration that a lower-privileged user can set — particularly around service/process enumeration and disk/network queries. Even after patching, this is good hygiene, since it tells you whether this was ever practically exploitable in your deployment.

  4. Treat exec()-based tooling as higher risk generally. If your own code shells out via child_process.exec() with concatenated strings anywhere, apply the same fix pattern the maintainer used: switch to execFile()/spawn() with an argument array (avoiding a shell entirely), or rigorously allow-list and escape any values before they reach a shell string.

  5. Add continuous dependency scanning to CI, not just a one-time fix. A point-in-time upgrade doesn't protect you from the next disclosure. Wire software composition analysis into your pipeline so new advisories against packages already in your tree — direct or transitive — surface automatically and get triaged before merge.

  6. Verify via SBOM. Generate or pull your current SBOM and confirm no build artifact, container image, or deployed service still references a systeminformation version below 5.3.1. This is the only way to be confident across microservices, monorepos, and older long-lived branches simultaneously.

How Safeguard Helps

Safeguard is built to answer the question that CVSS alone can't: is this vulnerability actually reachable in my code? For a case like CVE-2021-21315, Safeguard's reachability analysis traces whether your application's call graph actually invokes the vulnerable systeminformation functions with data that can be influenced by an untrusted source, cutting through dependency-list noise to prioritize the instances that matter. Griffin, Safeguard's AI security agent, triages findings like this automatically — correlating the advisory, your SBOM, and your source to explain exploitability in plain language and rank it against everything else in your backlog. Continuous SBOM generation and ingest ensure that transitive exposure to packages like systeminformation is caught the moment it enters a lockfile, even buried several dependencies deep, rather than surfacing months later in a scheduled scan. And when a fix is available, Safeguard can open an auto-fix pull request that bumps the dependency and regenerates the lockfile, so remediation ships in minutes instead of sitting in a backlog. Together, these capabilities turn a critical-severity advisory into a scoped, verifiable, fast-to-close action item.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.