Skip to content

Permissions

If you have hyprland-guiutils installed, you can make use of Hyprland’s built-in permission system. For now, it only has a few permissions, but it might include more in the future.

Tip

If you care about this permissions system, you probably also care about blocking access to Hyprland’s IPC sockets. Hyprland itself cannot enforce this; consult the documentation for your application sandbox of choice.

Permissions

Permissions work a bit like Android ones. If an app tries to do something sensitive with the compositor (Hyprland), Hyprland will pop up a notification asking you if you want to let it do that.

Note

Before setting up permissions, make sure you enable them by setting hl.config({ ecosystem = { enforce_permissions = true } }), as it’s disabled by default.

Configuring permissions

Important

Permissions set up in the config are not reloaded on-the-fly and require a Hyprland restart for security reasons.

Configuring them is simple:

hl.permission({ binary, type, mode })

For example:

hl.permission({ binary = "/usr/bin/grim", type = "screencopy", mode = "allow" })

will allow /usr/bin/grim to always capture your screen without asking, and

hl.permission({ binary = "/usr/bin/appsuite-.*", type = "screencopy", mode = "allow" })

will allow any app whose path starts with /usr/bin/appsuite- to capture your screen without asking.

Permission modes

There are 3 modes:

  • allow: Don’t ask, just allow the app to proceed.
  • ask: Pop up a notification every time the app tries to do something sensitive. These popups let you Deny, Allow until the app exits, or Allow until Hyprland exits.
  • deny: Don’t ask, always deny the application access.

Permission list

screencopy

  • Default: ASK
  • Access to your screen without going through xdg-desktop-portal-hyprland. Examples include: grim, wl-screenrec, wf-recorder.
  • If denied, will render a black screen with a “permission denied” text.
  • Why deny? For apps/scripts that might maliciously try to capture your screen without your knowledge by using Wayland protocols directly.

plugin

  • Default: ASK
  • Access to load a plugin. Can be either a regex for the app binary, or plugin path.
  • Do not allow hyprctl to load your plugins by default (attacker could issue hyprctl plugin load /tmp/my-malicious-plugin.so) - use either deny to disable or ask to be prompted.

keyboard

  • Default: ALLOW
  • Access to connecting a new keyboard. Regex of the device name.
  • If you want to disable all keyboards not matching a regex, make a rule that sets DENY for .* as the last keyboard permission rule.
  • Why deny? Rubber duckies, malicious virtual/USB keyboards.

cursorpos

  • Default: ASK
  • Access to your cursor position and cursor image via Wayland protocols directly.
  • Why deny? Prevents apps from silently tracking where your cursor is without going through xdg-desktop-portal.

input-capture

  • Default: ASK
  • Access to capture all input events from the compositor (keyboard, pointer, touch).
  • Why deny? Prevents apps from maliciously capturing all user input without your consent.

Notes

Portals

xdg-desktop-portal implementations (including XDPH) are just regular applications. They will go through permissions too. You might want to consider adding a rule like this:

hl.permission({ binary = "/usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland", type = "screencopy", mode = "allow" })

if you are not allowing screencopy for all apps.

NixOS

NixOS does not have static paths for the binaries, so regex must be used. These example rules allow grim and xdg-desktop-portal-hyprland to copy the screen:

hl.permission({ binary = "/nix/store/[a-z0-9]{32}-grim-[0-9.]*/bin/grim", type = "screencopy", mode = "allow" })
hl.permission({ binary = "/nix/store/[a-z0-9]{32}-xdg-desktop-portal-hyprland-[0-9.]*/libexec/.xdg-desktop-portal-hyprland-wrapped", type = "screencopy", mode = "allow" })

When rendering the configuration with Nix itself, string interpolation can also be used. Be aware that if the path contains special regex characters (e.g. +) they need to be escaped:

hl.permission({ binary = "${lib.getExe pkgs.grim}", type = "screencopy", mode = "allow" })
hl.permission({ binary = [[${lib.escapeRegex (lib.getExe config.programs.hyprlock.package)}]], type = "screencopy", mode = "allow" })
hl.permission({ binary = [[${pkgs.xdg-desktop-portal-hyprland}/libexec/\.xdg-desktop-portal-hyprland-wrapped]], type = "screencopy", mode = "allow" })

BSD

On some BSD systems paths might not work. In such cases, you might want to disable permissions altogether, by setting:

hl.config({
  ecosystem = {
    enforce_permissions = false
  }
})

Otherwise, you will have no config control over permissions (popups will still work, although they will not show paths, and “remember” will not be available).

Last updated on