Skip to content

ParaShells — Parallels Desktop for Mac local privilege escalation: a quote in an appliance folder name becomes tar --use-compress-program running as root (CVE-2026-90894, CVSS 7.8, JFrog, Sep 14, 2026)

Summary

JFrog Security Research (Yuval Moravchick, published September 14, 2026, blog "ParaShells: Parallels Desktop Turns Appliance Install Into a Root Shell") documents CVE-2026-90894 (CVSS 7.8, high) in Parallels Desktop for Mac < 27.0.0: any local, unprivileged, unsigned process can obtain a root shell through the appliance-install path. Parallels runs prl_disp_service as root and exposes it on the world-writable socket /var/run/prl_disp_service.socket; PrlSrv_LoginLocal accepts peer credentials with no Parallels signature requirement and no admin-group requirement. After that unprivileged login, PrlSrv_InstallAppliance lets the caller choose the appliance destination folder (sVmParentPath), and the daemon unpacks with a single command stringtar -xf "%1" -C "%2" — chopped into words by Qt QProcess::splitCommand. A double-quote embedded in the folder name closes the quoting early, and the leftover text becomes extra tar flags; macOS tar then honors --use-compress-program=, executing the named program as root. Demonstrated root on 26.4.0 (57513). In 27.0.0 the daemon starts tar as a fixed argv list, so the same quote stays literal — but hosts that stay on the 26.x line (including 26.4.2) never got that change.

Tags

Vulnerability mechanics

  1. Reachability: /var/run/prl_disp_service.socket is srwxrwxrwx (world-writable). PrlSrv_LoginLocal accepts any local peer's credentials — an unsigned, non-admin process logs in successfully (PrlUsrCfg_IsLocalAdministrator stays 0, and that is not checked).
  2. Injection: PrlSrv_InstallAppliance takes sVmParentPath (the appliance folder) from the caller. The root daemon builds one string, tar -xf "<archive>" -C "<folder>", and passes it through QProcess::splitCommand, which splits on whitespace after quote handling. A folder name like /tmp/sprl_p_<uid>" --use-compress-program=/tmp/u<uid> " terminates the quoted segment and injects the flag; the archive's PackageURL/PackageMd5 just need to be a matching file:// tar.
  3. Execution: macOS tar runs the --use-compress-program target as root (uid 0) during extract. InstallAppliance may still return error -41508 afterward — the proof is the root marker, not the job status.
  4. Fix shape: 27.0.0 invokes tar with a fixed argv array, so the quote survives as part of a literal directory name (created on disk, never parsed as flags). 26.x line is unfixed — there is no patch for staying on 26.x.

Defender heuristics

  1. Move hosts to 27.0.0+; the 26.x branch (through at least 26.4.2) has no extract-path fix. Parallels KB 131168 tracks the release notes.
  2. Until upgraded, restrict local access: any local account — including low-value service/shared accounts — can reach the dispatcher socket on a vulnerable install. This collapses the "local foothold is low severity" assumption on Macs running Parallels.
  3. Hunt artifacts: directories under /tmp matching sprl_p_* containing an embedded quote; tar processes spawned by prl_disp_service with --use-compress-program in argv; unexpected uid-0 children of the extract during an appliance install; InstallAppliance returning -41508 alongside a root-executed marker.
  4. Pattern-level: the durable lesson is "never build a command as one string and split it yourself" — quoting bugs in concatenated command strings turn a path parameter into flags, and --use-compress-program-style options (also tar --checkpoint-action, git -c, ssh -o) turn flags into code execution. Audit any root daemon that shells out with caller-influenced paths.

Sources