# REPRO-2026-00100: systeminformation: Command Injection via locate Output ## Summary Status: published Severity: high Type: security Confidence: Unknown ## Identifiers REPRO ID: REPRO-2026-00100 GHSA: GHSA-5vv4-hvf7-2h46 CVE: CVE-2026-26318 ## Package Name: systeminformation Ecosystem: npm Affected: <= 5.30.7 Fixed: 5.31.0 ## Root Cause # 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` ## Reproduction Details Reproduced: 2026-02-19T21:13:58.512Z Duration: 1124 seconds Tool calls: 110 Turns: 77 Handoffs: 2 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00100 pruva-verify GHSA-5vv4-hvf7-2h46 pruva-verify CVE-2026-26318 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00100&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00100/artifacts/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - GitHub Advisory: https://github.com/advisories/GHSA-5vv4-hvf7-2h46 - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-26318 ## Artifacts - repro/rca_report.md (analysis, 9131 bytes) - repro/reproduction_steps.sh (reproduction_script, 11077 bytes) - bundle/ticket.md (ticket, 9100 bytes) - bundle/source.json (other, 11511 bytes) - bundle/ticket.json (other, 21320 bytes) - logs/direct_test_output.log (log, 548 bytes) - logs/test_injection.js (other, 1850 bytes) - logs/test_vuln_behavior.js (other, 1738 bytes) - logs/variant_vuln_clone.log (log, 681 bytes) - logs/test3_regex_patterns.log (log, 1067 bytes) - logs/updatedb.log (log, 0 bytes) - logs/test_fixed_behavior.js (other, 2160 bytes) - logs/clone.log (log, 676 bytes) - logs/locate_output.log (log, 85 bytes) - logs/direct_test.js (other, 2848 bytes) - logs/test1_vuln_behavior.log (log, 470 bytes) - logs/test_output.log (log, 1056 bytes) - logs/variant_fixed_clone.log (log, 682 bytes) - logs/test_regex_patterns.js (other, 1964 bytes) - logs/test2_fixed_behavior.log (log, 478 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00100 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00100/artifacts/repro/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00100 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev