#16192·rustdesk

macOS: Host cannot exit Privacy Mode locally; requires controller to disconnect

Author: zgfeng115Created Sep 13, 2026Updated Sep 13, 2026

Describe the bug

On macOS, once a controller enables Privacy Mode on the controlled (host) machine, the host has no way to exit Privacy Mode locally. The only way to restore the host's desktop is for the controller to disconnect the session entirely. If the controller crashes, force-quits, or the connection drops uncleanly (no clean FIN), the host appears to be stuck indefinitely with the screen blanked and local input blocked.

To Reproduce

  1. Controller connects to a macOS host via RustDesk.
  2. Controller enables Privacy Mode.
  3. On the host, attempt to exit Privacy Mode locally — no keyboard shortcut, tray menu item, or other local affordance exists.
  4. The host stays blanked (black screen) with local keyboard/mouse blocked until the controller explicitly disconnects.

Expected behavior

The host should have some local means of escaping Privacy Mode — e.g., a reserved hotkey that bypasses the event tap, or an automatic timeout/heartbeat-based release if the controller connection becomes unresponsive.

Root cause analysis

  • src/privacy_mode.rs defines the PrivacyMode trait; turn_off_privacy is gated on the conn_id of the connection that originally enabled it — there's no "local host" variant of this id.
  • The macOS implementation (src/privacy_mode/macos.rs, backed by native code in src/platform/macos.mm, introduced in #14102) blanks the display via CGSetDisplayTransferByTable (gamma table set to black) and blocks local input via a CGEventTap.
  • In src/server/connection.rs, turn_off_privacy is only invoked from two places: (1) an explicit toggle-off message from the controller, and (2) cleanup when that connection closes normally.
  • src/tray.rs has no Privacy Mode related menu item — there is no local UI entry point to disable it.
  • Critically, because the same CGEventTap that implements the block also swallows all local keyboard/mouse events, even a local hotkey escape would need to be wired in before or outside that tap to have any chance of being received.

Related: #84 in rustdesk-server describes the same structural issue (no way to disable Privacy Mode except by disconnecting) in a more general context; it's been open with no maintainer response. This report focuses specifically on the macOS CGEventTap/gamma-table implementation, where the lack of a local exit is architecturally reinforced by the input-blocking mechanism itself.

Suggested fix direction (for discussion, not a commitment to submit a PR)

  • Register a dedicated, higher-priority CGEventTap for a reserved emergency-exit key combination before installing the privacy-blocking tap, so it isn't swallowed.
  • Or: add a heartbeat/liveness check on the controlling connection and force turn_off_privacy if the controller becomes unresponsive beyond a timeout, covering the case where a clean disconnect message/event never arrives.

Environment

  • RustDesk version: 1.4.9
  • OS: macOS 27.0 (Build 26A428)