Browse the docs

Permissions

A package grants the smallest set of permissions that lets the app’s main feature work, with a comment on each. Everything the app can do beyond that is left off and documented as a flatpak override command in the app’s description, so each user decides. Permissions show on every app’s page.

  • Files: grant the directory the app works in by default (xdg-pictures for a screenshot tool, xdg-music for a player), not home. Files opened through the file chooser need no grant at all.
  • The app’s own ~/.something: Flatpak only redirects the XDG directories. An app that writes a dotdir in your home loses it on every restart unless the package grants it.
  • High-risk permissions (running commands outside the sandbox, devices, the whole home directory) are declared in flatpark.yml, argued for in the PR and reviewed by a maintainer. They are granted when the app’s main feature needs them, or when leaving them out would take more overrides than a user can be expected to manage. The app page marks them with a warning.
  • The developer decides for their own app. When upstream says how they want the package to behave, we follow it, and declare what it needs.
For agents

Optional capabilities as overrides

Put them in the metainfo description, where the app page shows them, with a line that undoes them:

<p>A few optional capabilities are not granted by default; enable the ones you
   need with "flatpak override":</p>
<ul>
  <li>Reuse your host SSH keys: <code>flatpak override --user --filesystem=~/.ssh:ro org.electerm.Electerm</code></li>
  <li>Serial ports: <code>flatpak override --user --device=all org.electerm.Electerm</code></li>
  <li>Undo all of these: <code>flatpak override --user --reset org.electerm.Electerm</code></li>
</ul>

Adapted from Electerm. That other apps on Flathub grant home makes a broad grant acceptable, not necessary; ship the narrow one.

Home-directory dotdirs

Inside the sandbox $HOME is still /home/<user>, an almost empty overlay; only XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_CACHE_HOME point into ~/.var/app/<id>/. An app that writes $HOME/.app (Java’s user.home, Node’s os.homedir(), Go’s UserHomeDir) writes into a tmpfs that disappears on exit. Check with flatpak run --command=sh <id> -c 'echo $HOME; ls -la $HOME', and after a restart.

  • The app’s own directory: --filesystem=~/.app:create. It lives in the real home, so it is shared with a native install and the user can find it. Or --persist=.app, which keeps it under ~/.var/app/<id>/ instead. --persist is ignored when home or host is also granted.
  • Another tool’s directory the app reads (an editor reading CLI configs): grant it without :create. With it, every tool the user never installed gets an empty directory in their home, and apps that take “the directory exists” to mean “the tool is installed” get it wrong.
  • A lock file in that directory: apps that keep their single-instance lock there start a second copy when it is lost, which then fails on a port the first one holds.

This is the most common severe bug in our history: four apps lost settings or data on every restart for this reason before it was understood.

Single files

Don’t grant a single file (--filesystem=~/.app.json) that the app rewrites by saving a temporary file and renaming it over the original. The grant is a bind mount on that file, and the rename fails with EBUSY. Grant the directory instead.

Declaring high-risk permissions

List them under policy.dangerous_permissions in flatpark.yml and explain each in the PR. Reaching outside the sandbox (--filesystem=host, --filesystem=/, --talk-name=org.freedesktop.Flatpak) is granted only when it is declared, argued in the PR, needed by the app’s feature, and reviewed by a maintainer.

Enpass is the example. It checks which browser is behind its extension’s local connection by running lsof and reading /proc, which can’t work in the sandbox. Instead of patching Enpass, the package puts small lsof, readlink and cat scripts on PATH that run the real commands on the host through flatpak-spawn --host. Nothing is injected into Enpass, but the package needs --talk-name=org.freedesktop.Flatpak, which lets the app run any host command: it declares that, and its page says so.

Declaring changes to how the app runs

Anything a package does beyond starting the vendor’s build goes under packaging: in flatpark.yml, one entry per change, with a sentence in English and Chinese. The site shows the resulting packaging level.

Kind When Level Allowed for
support-files Libraries or tools added next to the app (prebuilt stacks, a second download) Adapted All; derived from the manifest, not declared
seeded-config Settings written before first launch, e.g. turning off an updater that can’t work Adapted All
injected-code An LD_PRELOAD library or other code in the app’s process Modified Closed source only
file-change Files in the vendor’s build added, removed or changed Modified Closed source only
runtime-install The vendor’s installer runs at first launch with parts stood in for or its result changed (running it unmodified is not a change) Modified Closed source only
host-command The app can run commands on the host (flatpak-spawn --host) Reduced isolation All, declared
sandbox-off The app’s own sandbox is turned off (--no-sandbox, WEBKIT_DISABLE_SANDBOX) Reduced isolation All, declared

audit-descriptor.mjs fails a package whose scripts show one of these without the matching entry. A wrapper that only sets environment variables or flags is Unmodified and declares nothing. Leaving out parts of the vendor package that can’t work in Flatpak (a setuid chrome-sandbox, a pkexec updater, a file-manager extension) is not a change.

An open-source app that can’t work without injected code or changed files is not listed; the fix belongs upstream.

When the developer has asked

If upstream states what they want — more permissions, fewer, a different default — apply it in its own PR, declare what needs declaring, and link their request. The narrow default above is for when they haven’t said.

Edit this page on GitHub