Human
Machine
REPRO-2026-00100 HIGH Command Injection
Verified
systeminformation: Command Injection via locate Output
systeminformation (npm) Feb 19, 2026
What's the vulnerability?
Inside the versions() function, when detecting the PostgreSQL version on Linux, the code does this:
// lib/osinfo.js — lines 770-776
exec('locate bin/postgres', (error, stdout) => {
if (!error) {
const postgresqlBin = stdout.toString().split('\n').sort();
if (postgresqlBin.length) {
exec(postgresqlBin[postgresqlBin.length - 1] + ' -V', (error, stdout) => {
// parses version string...
});
}
}
});
Here's what happens step by step:
- It runs
locate bin/postgresto search the filesystem for PostgreSQL binaries - It splits the output by newline and sorts the results alphabetically
- It takes the last element (highest alphabetically)
- It concatenates that path directly into a new
exec()call with+ ' -V'
No sanitizeShellString(). No path validation. No execFile(). Raw string concatenation into exec().
The locate command reads from a system-wide database (plocate.db or mlocate.db) that indexes all filenames on the system. If any indexed filename contains shell metacharacters — specifically semicolons — those characters will be interpreted by the shell when passed to exec().
Root Cause Analysis
# Root Cause Analysis Report
## GHSA-5vv4-hvf7-2h46: Command Injection via Unsanitized `locate` Output in `versions()`
## Summary
The `systeminformation` npm package (versions <= 5.30.7) contains a command injection vulnerability in the `versions()` function when detecting PostgreSQL version on Linux. The vulnerable code executes `locate bin/postgres` and passes the unsanitized output directly to `exec()` by concatenating the retrieved path with ` + ' -V'`. An attacker can create a file with a malicious path containing shell metacharacters (such as semicolons) that, when indexed by the locate database and sorted, becomes the selected path. This allows arbitrary command execution when any application using the library calls `si.versions('postgresql')`.
## Impact
- **Package:** systeminformation (npm)
- **Affected Versions:** <= 5.30.7
- **Fixed Version:** 5.31.0
- **CVE:** CVE-2026-26318
- **CVSS Score:** 8.8 (HIGH)
- **CWE:** CWE-78 (OS Command Injection)
- **Platform:** Linux only (the vulnerable code path is within an `if (_linux)` block)
### Risk Level and Consequences
- **Severity:** HIGH
- **Attack Vector:** Local (requires ability to create files on the filesystem)
- **Privileges Required:** Low (any user who can create files that get indexed by `updatedb`)
- **Impact:** Arbitrary command execution with the privileges of the Node.js process
### Attack Scenarios
1. **Shared Hosting/Multi-Tenant:** A low-privileged user creates malicious files; a monitoring agent using `systeminformation` executes the injected commands
2. **CI/CD Pipeline Poisoning:** Malicious build steps create crafted filenames; pipeline reporting triggers command execution
3. **Container Escape:** Compromised containers create malicious files on shared volumes; host monitoring agents execute injected commands
## Root Cause
### Technical Analysis
The vulnerability exists in `lib/osinfo.js` at lines 770-776:
```javascript
exec('locate bin/postgres', (error, stdout) => {
if (!error) {
const postgresqlBin = stdout.toString().split('\n').sort();
if (postgresqlBin.length) {
exec(postgresqlBin[postgresqlBin.length - 1] + ' -V', (error, stdout) => {
// ...
});
}
}
});
```
**Why this is vulnerable:**
1. **Unsanitized external input:** The `locate` command reads from a system-wide database (`plocate.db` or `mlocate.db`) that indexes all filenames. Attackers can create files with shell metacharacters in their paths.
2. **Shell interpretation via `exec()`:** Node.js's `exec()` function passes commands to `/bin/sh -c`, which interprets shell metacharacters. A path like `/var/tmp/x;touch /tmp/FILE;/bin/postgres` becomes three separate commands when concatenated with ` + ' -V'`:
- `/var/tmp/x` (fails silently)
- `touch /tmp/FILE` (attacker's command executes)
- `/bin/postgres -V` (runs normally)
3. **Alphabetical sort selection:** The code sorts paths and takes the last element. Since `/var/` sorts alphabetically after `/usr/`, a malicious path in `/var/tmp/` naturally becomes the selected one.
4. **Missing validation:** No `sanitizeShellString()`, no path validation, no use of `execFile()` (which doesn't spawn a shell).
### Suggested Fix
Replace `exec()` with `execFile()` for the PostgreSQL binary version check:
```javascript
const { exec, execFile } = require('child_process');
exec('locate bin/postgres', (error, stdout) => {
if (!error) {
const postgresqlBin = stdout.toString().split('\n')
.filter(p => p.trim().length > 0)
.sort();
if (postgresqlBin.length) {
// Use execFile instead of exec - does not spawn a shell
execFile(postgresqlBin[postgresqlBin.length - 1], ['-V'], (error, stdout) => {
// ... parse version
});
}
}
});
```
Additionally, validate paths against a safe pattern:
```javascript
const safePath = /^[a-zA-Z0-9/_.-]+$/;
const postgresqlBin = stdout.toString().split('\n')
.filter(p => safePath.test(p.trim()))
.sort();
```
## Reproduction Steps
The reproduction script is located at `repro/reproduction_steps.sh`.
### What the Script Does
1. **Environment Setup:** Installs `plocate` if not present (required for the vulnerable code path)
2. **Clone Vulnerable Code:** Clones systeminformation v5.30.7 (the last vulnerable version)
3. **Create Malicious Path:** Creates a file at `/var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin/postgres` containing shell metacharacters
4. **Update Locate Database:** Runs `updatedb` to index the malicious file
5. **Verify Database:** Confirms the malicious path appears in `locate bin/postgres` output
6. **Execute Exploit:** Runs a Node.js script that mimics the vulnerable code behavior:
- Executes `locate bin/postgres`
- Splits and sorts the output
- Selects the last path (alphabetically highest)
- Executes `selectedPath + ' -V'` via `exec()`
7. **Verify Injection:** Checks if `/tmp/SI_RCE_PROOF` was created, proving command injection
### Expected Evidence
Successful reproduction creates the file `/tmp/SI_RCE_PROOF`, which was touched via the injected `touch /tmp/SI_RCE_PROOF` command embedded in the malicious path.
**Successful output includes:**
```
!!! WARNING: Selected path contains semicolon - will cause command injection !!!
Executing vulnerable command: /var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin/postgres -V
*** COMMAND INJECTION SUCCESSFUL - Proof file exists! ***
*** VULNERABILITY CONFIRMED ***
```
## Evidence
### Log Files
All logs are stored in `$ROOT/logs/`:
- `logs/clone.log` - Git clone output
- `logs/updatedb.log` - Database update output (if applicable)
- `logs/locate_output.log` - Output from `locate bin/postgres`
- `logs/direct_test_output.log` - Main test execution output
- `logs/direct_test.js` - The test script that mimics vulnerable code
### Key Evidence Excerpts
From `logs/direct_test_output.log`:
```
Found paths: [
'/usr/lib/postgresql/16/bin/postgres',
'/var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin/postgres'
]
Selected path (last after sort): /var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin/postgres
!!! WARNING: Selected path contains semicolon - will cause command injection !!!
Executing vulnerable command: /var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin/postgres -V
Command executed. Checking for proof file...
*** COMMAND INJECTION SUCCESSFUL - Proof file exists! ***
*** VULNERABILITY CONFIRMED ***
```
Proof file creation:
```
-rw-r--r-- 1 root root 0 Feb 19 20:54 /tmp/SI_RCE_PROOF
```
### Vulnerable Code Location
`repos/systeminformation/lib/osinfo.js` lines 770-776:
```javascript
exec('locate bin/postgres', (error, stdout) => {
if (!error) {
const postgresqlBin = stdout.toString().split('\n').sort();
if (postgresqlBin.length) {
exec(postgresqlBin[postgresqlBin.length - 1] + ' -V', (error, stdout) => {
```
## Recommendations / Next Steps
### Immediate Actions
1. **Upgrade to v5.31.0 or later** - The vulnerability is fixed in version 5.31.0
2. **Audit existing deployments** - Check if `systeminformation` is used in production applications
3. **Monitor for exploitation** - Check for suspicious files in the locate database
### Code Review
Review all uses of `exec()` in the codebase to ensure:
- No unsanitized external input is passed to `exec()`
- `execFile()` is used when shell interpretation is not needed
- Input validation is performed on paths from external sources
### Testing Recommendations
1. Add security regression tests that attempt command injection via various inputs
2. Implement SAST scanning to detect dangerous patterns like `exec(variable + string)`
3. Consider using a shell-escape library for any dynamic command construction
## Additional Notes
### Idempotency Confirmation
The reproduction script has been tested multiple times and produces consistent results:
- Each run cleans up previous test artifacts
- The malicious file is recreated each time
- The locate database is updated each run
- The vulnerability is successfully demonstrated on every execution
### Edge Cases and Limitations
1. **Locate database timing:** In production, the `updatedb` command runs on a daily schedule. The malicious file may not be indexed immediately after creation.
2. **Sort order dependency:** The exploit relies on the malicious path sorting alphabetically after legitimate paths (`/var/` > `/usr/`). Paths starting with characters after 'v' in the alphabet would also work.
3. **PostgreSQL presence:** The vulnerable code path only executes if `locate bin/postgres` returns results. Systems without PostgreSQL installed would not trigger this specific code path (though the pattern may exist elsewhere).
4. **Root requirements:** Updating the locate database typically requires root privileges or the `plocate` group membership. However, the database is updated automatically by system timers, so attacker-created files will eventually be indexed.
### Related Files
- Vulnerable source: `repos/systeminformation/lib/osinfo.js`
- Reproduction script: `repro/reproduction_steps.sh`
- Test scripts: `logs/direct_test.js`, `logs/test_injection.js`
- Package metadata: `repos/systeminformation/package.json`
One Command
Verify with pruva-verify
Run the Pruva CLI to automatically fetch and execute the reproduction script.
pruva-verify REPRO-2026-00100 or
pruva-verify GHSA-5vv4-hvf7-2h46 or
pruva-verify CVE-2026-26318 Install:
curl -fsSL https://pruva.dev/install.sh | sh Or Run Manually
1
Download the script
curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00100/artifacts/reproduction_steps.sh 2
Make executable
chmod +x reproduction_steps.sh 3
Run the script
./reproduction_steps.sh Run in a VM, container, or disposable environment. This exploits a real vulnerability.
How Pruva Reproduced This
Watch the AI agent's step-by-step process.
Loading session...
Artifacts
No artifacts available