# ParaShells: Parallels Desktop Turns Appliance Install Into a Root Shell

Unsigned local user exploits world-writable prl_disp_service socket and quote-breaking sVmParentPath to inject tar --use-compress-program, running code as root.

- Payout: Research
- Severity: high
- Program: Parallels Desktop
- Found by (vendor credit): Yuval Moravchick | JFrog
- Disclosed: 2026-09-15
- CVE: CVE-2026-90894
- Write-up quality: 8/10
- Original: https://jfrog.com/blog/parallels-desktop-turns-appliance-install-into-root-shell/
- Library page: https://bugbountylibrary.com/r/blog%3Ajfrog-com-blog-parallels-desktop-turns-appliance-install-into-root-shell
- Tags: area:os domain:desktop impact:privesc impact:rce kind:research platform:threat-intel sev:high technique:source-review vuln:auth-bypass vuln:command-injection vuln:misconfiguration vuln:privilege-escalation

**Target:** prl_disp_service root helper / InstallAppliance extract path
**Root cause:** InstallAppliance formats a tar command string with single-quoted %1/%2, then Qt splitCommand re-tokenizes it; a quote in sVmParentPath closes the quote early and injects tar flags. LoginLocal trusts kernel peer credentials with no Team ID check, and the dispatcher socket is 0777.
**Steps:**
1. Confirm `/var/run/prl_disp_service.socket` is mode 0777 and Desktop is 26.4.0 (57513).
2. Connect to the socket from an unsigned client and call `PrlSrv_LoginLocal`; succeeds via peercred for non-admin user.
3. Build fake appliance config with `<PackageURL>file:///tmp/prl_appl_rce_payload_<uid>.tar</PackageURL>` plus matching MD5/size.
4. Create directory named `/tmp/sprl_p_<uid>" --use-compress-program=/tmp/u<uid> "` and place same archive bytes at `/tmp/sprl_p_<uid>`.
5. Write `/tmp/u<uid>` script that writes a root marker and drops `/etc/sudoers.d/prl-rce-<uid>` with NOPASSWD.
6. Call `PrlSrv_InstallAppliance` with that sVmParentPath; tar runs the compress-program as root despite extract error -41508.
7. Run `sudo -i` after marker shows UCP_UID=0.
**How found:** Code-reading of the InstallAppliance extract template `tar -xf "%1" -C "%2"` combined with knowledge that Qt QProcess::splitCommand re-parses quotes; noticed socket was world-writable and LoginLocal accepted unsigned clients, then hypothesized a quote in sVmParentPath would inject tar flags.
**Exploitation:** Local unprivileged process connects to the world-writable dispatcher socket, authenticates via peercred, and submits an appliance install whose parent path breaks the tar command quoting. The injected --use-compress-program runs an attacker script as root when tar opens the archive; script plants a NOPASSWD sudoers fragment for a root shell.
**Escalation:** Root script writes /etc/sudoers.d fragment granting the low-priv user passwordless sudo, converting code exec into persistent interactive root.
**Insight:** When a privileged helper builds a command string and passes it through Qt splitCommand (or any shell-like tokenizer), a quote in any interpolated path becomes argv injection even without a shell; look for feature flags of the child binary like tar --use-compress-program or --to-command as root-exec primitives.
