Flatpak is not a sandbox

(23.11.2022)

tldr; The myth that flatpak apps provide a sandboxed environment is an illusion. Flatpaks are containerized applications that provide limited isolation by default and should be described as such.


(the term flatpak and flatpak applications is used synonymously in this text)

Flatpak is an incredible project that has contributed a number of very useful features to Linux desktop environments, helping define standards along the way. Whether flatpaks are the future of application distribution is yet to be seen, but there is one thing that it certainly is not: Sandboxed.

The core technology that provides the sandbox environment for flatpaks is quite solid. With bubblewrap as a simple and unprivileged sandboxing tool for Linux namespaces and seccomp filter, the project is build with a minimal attack surface and thereby avoids an increased attack surface unlike other sandboxing projects such as firejail, which runs as a suid root process without ever dropping privileges for good. From this software architectural perspective, flatpaks are off to a very good start. But it takes quite a bit more to build a solid sandbox that isolates a potentially compromised process from them rest of the system.

What is a sandbox?

Sandboxing as a security feature has been around for a while, with browsers such as chromium taking a lead role in bringing the technology to desktop applications. While simple “sandboxes” like chroot have been around for decades, the implementation inside a complex multi process application like modern web browsers is on another level and required a significant development effort to bring this technology to where it is today. The documentation for the chromium sandbox provides a good first overview about the technology for those who are interested about the technical details [1].

In short, a sandbox provides an isolated runtime environment that restricts the process to allow only the minimal required actions (Principle of least privilege). Before a sandbox can be implemented inside a target application, a security boundary needs to be defined to establish which actions are to be permitted for the application process. By definition, any action that would breach the limits of these boundaries is a software vulnerability. Sandbox escape vulnerabilities can occasionally be found among the patched vulnerabilities of modern browsers like chromium and firefox, as well as in the sandbox frameworks of iOS and Android.

Types of sandboxes

Depending on the application and defined security boundaries, there are different approaches to implement a sandbox.

The most simple but also least effective sandbox type is the container or wrapper sandbox that builds an isolated process environment and then executes the target application inside. This kind of sandbox will require permissions for all actions the target application process executes during its entire lifetime, from initializing the configuration to rendering user supplied data (e.g. files, webpages). If the application at some point during its runtime requires access to a resource, it will keep this access indefinitely, even if access is only required during the initialization phase of the application. How effective this kind of sandbox is, depends a lot on the required permissions, but in general it cannot nearly reach the level of process isolation that other types of sandboxes can achieve.

A significantly more effective sandbox can be implemented by native sandboxing through the application process itself. If the application is simple enough, it is possible to implement effective sandboxing without significant efforts other then analyzing what kind of access the application requires. There are a few examples of these types of sandbox implementation like file[2] or zathura[3], which both use seccomp filter to restrict the permitted system calls their process can execute. Unlike with container/wrapper sandboxes, these sandbox implementations can set additional restrictions during their lifetime, thereby allowing a significantly reduced attack surface. For example, zathura will setup a GUI, load its configuration files unrestricted (which is harmless anyway) and before the dangerous part of parsing the target document is executed, it loads a seccomp filter that prevents the majority of system calls from being executed. By the time the target document is loaded and a possible parsing vulnerability may lead to code execution, the process is no longer able to open new files with write permissions or access sockets. These kinds of restrictions are not possible inside a container sandbox and provide a significant advantage. Any developers interested in using this kind of sandboxing should take a look at libseccomp[4].

When an application is more complex and cannot be effectively restricted at a certain point during its runtime, a broker sandbox architecture is required. This kind of sandbox is what Chromium and Firefox use to establish effective isolation for any process that has a significant attack surface. This is basically implemented through a multi process software architecture, where a broker process will be used to provide any requested resources to the sandboxed child processes, which do not have any access permissions themselves. Any time the child process needs access to a resource, it will have to request it from the broker, which will verify if the request is safe/valid and then provide it to the child process. The level of sandbox isolation achieved by this kind of sandbox is so significant, that sandbox escape vulnerabilities are valued twice as high as code execution in bug bounty programs[5]. Whenever a new zero day exploit for these sandboxed web browsers is revealed, it usually utilizes a number of chained exploits that not only achieve code execution, but also have to defeat the sandbox isolation with increasing efforts, all while using vulnerabilities that often sell for millions. If every application had a sandbox environment like chromium/firefox, desktop application security would be on a whole different level and could actually compare to app isolation that is already established on iOS and Android. As of today, Linux desktop applications (and Windows as well) is a far cry from the isolation that is already common on on mobile platforms. While full exploit chains for desktop browsers (on Linux/Windows/Mac) already sell for hundreds of thousands, a full exploit chain on android is valued at several millions already[6].

Sandbox objectives

Not every calculator application out there needs a sandbox. But what applications would benefit from sandboxing and increase the security of a desktop system against realistic threats? To answer this one only needs to look for applications that are actually targets by existing exploits. The biggest attack surface of modern desktop systems is certainly web browsers and fortunately those are already using sandboxing for decades. Additionally any applications that parse complex file formats which are commonly used to exchange data would be at risk. This would affect things like PDFs and office documents, but also media files like image, video and audio. Any application that parses such files should make sure that a vulnerability in a library used to process these file formats does not automatically compromise the entire application or even the whole system. The applications that would benefit the most from a sandbox would therefore be things like PDF readers, image viewers, media players and office suites. Many other applications like messenger clients often include features to parse media files as well and are just as much at risk. On the other hand, some applications wont benefit at all from sandboxing, especially when they cant be used effectively when run in a confined sandbox environment. Examples would include file managers or text editors that are required for basic system maintenance.

Flatpak isolation

Flatpak provides an isolated runtime environment using a container type sandbox to execute the target application inside. Combined with its approach for application packaging, it does so in a very clever and effective way. Additionally, the project has developed a way to provide certain resources to the isolated process by using a service called xdg-desktop-portals. These portals are basically dbus interfaces that can be used to access otherwise restricted resources. The Portal API is independent of Flatpak and can be used by otherwise packaged application as well, thereby providing a useful feature that may help establish a standard for desktop application sandboxing on Linux. By using portals, it is possible to approach a broker sandbox architecture, defining access APIs similar to runtime environments on mobile platforms.

Combining the container type sandbox and xdg-portals, flatpak can provide a significant and well build isolation from the rest of the system, at least in theory.

So why is flatpak not a sandbox?

In essence there are two issues that prevent flatpak from providing a real sandbox environment that rivals the sandbox definition used by the likes of chromium:

  1. Containers are not sandboxes

Flatpak combines a container type sandbox and some optional elements of a broker architecture through xdg-portals to achieve process isolation. This works well in the sense of containerization and establishes a separated runtime environment that provides all the resources required by the application. However it does not compare to a well defined sandbox that is build directly into the code with minimal privileges, designed for the specific thread model of the target application. Whats more is that while the use of xdg-portals which could actually increase the isolation significantly, it requires the application to use this API. This is very often not yet the case, resulting in a runtime environment that compares to containers more then it does to real sandboxes. And without the confined application using the portal APIs, flatpak provides just a container with rough isolation features. This is alright for the flatpak distribution model, but it does not provide a real sandbox that fits every applications requirements.

  1. Flatpak does not restrict features

The sandbox environments for flatpaks are defined to isolate the application without restricting its features. This simply cannot work without changing the application behavior itself. Some applications are starting to use the xdg-portal APIs and thereby allow for significantly improved isolation. However even with portals, there are some features that simply cannot work in flatpak without compromising the provided isolation. Or in other words, an effective sandbox will not allow for some features to work, but flatpak wants to provide them anyway.

One example is file access. Assuming for a moment that all future applications adapt the file chooser portal API, this will allow a sandboxed file access environment similar to that on mobile platforms. However, this API permits access to files or folders, chosen by the user in an interactive dialog. This is a very useful feature, but it does not provide the same freedom as access to the home directory does. Flatpak allows to expose the home directory and for all applications that do not use the portals file chooser API, this is the only alternative short of exposing specific directories. As a consequence, a significant number of flatpak app have unrestricted access to the users home directory, or even the complete host filesystem. On a typical Linux system that stores files such as .bashrc inside $HOME, this means sandbox escape already, as has been pointed out by others in the past. A flatpak mainfest could define that e.g. Libreoffice may only access ~/Documents as well as its own configuration files in .config and this would provide a fairly restrictive sandbox as far as file access is concerned. And while any attacker achieving code execution through libreoffice could still steal all files in ~/Documents, this will actually provide a sandbox that can’t be escaped simply by writing ‘./exploit’ into bashrc. But this would restrict features and that’s why we wont see effective restrictions like this in official flatpaks. A user may want to edit a file in $HOME after all and if that’s not possible, the user experience will not be the same as with the native application. I would like to add that this is a fairly reasonable approach for flatpak as application distribution platform. It just isn’t a sandbox.

Besides the file access isolation in flatpak there are other issues that cannot be properly addressed by flatpak when they are build to run out of the box on any distribution out there. One of the most well known problems is certainly the X11 window server, which as of today is still widely used. Flatpak won’t tell its users to move to a wayland WM to allow for secure sandboxing that blocks all communication to the X11 sockets. And even if it did and all flatpak users moved away from X11, there are still plenty of common applications out there that do not yet fully support wayland and require X11 servers. Consequently, flatpaks will use X11 when they have to and in many cases applications wont even be able to work without it. For those not aware, X11 does not implement any security separation between processes. Any process that can talk to the X11 server socket can control any other X11 window. That means that if a process can access the X11 socket, it can manipulate the input and output of any other process that uses X11. A flatpak app that is completely restricted but can access X11 simply needs to tell the X11 server to type ./exploit into another unconfined application window and that’s it. Its easy to test yourself[7]. If you have a xterm window running on the same X11 server as the confined application, you get automatic and unrestricted code execution. Bonus: If you have a root shell in your xterm, you get privilege escalation for free. This isn’t a flatpak issue and it isn’t news at all, but it is one example of a sandboxing pitfall that cannot be properly addressed by flatpak with its objective of being a general application distribution platform. To properly isolate the process from X11, flatpak would need to declare X11 support obsolete and then block access to the X11 socket completely. Which is actually a bit harder then it sounds like because like many services, X11 does not only support regular unix domain sockets that are accessed through the filesystem, but there are also abstract sockets, which live in the network namespace instead. So if your flatpak needs network access, you can’t just isolate X11 through file system isolation. The Linux permission system is designed to separate privileges between users and not between processes of the same user. To establish a new security boundary through sandboxing, there are a lot more pitfalls to address. For example if a user is logged in on tty1 and a process has access to /dev/tty1 then it can send commands to the users login shell and escape any process specific restrictions. All these pitfalls need to be addressed before effective sandboxing can be real and wherever an application feature requires a resource that cannot be safely sandboxed, this would require a change of the application itself which isn’t something flatpak does or wants to do.

Pentesting flatpak containers

To test the practical isolation provided by flatpak applications, I have setup a test system running debian bullseye (running gnome on wayland) and installed a few of the popular flatpaks from flathup. Since sandboxing is most useful for applications that need to parse complex file formats that may originate from untrusted sources, the apps targeted are Chromium/Chrome, Firefox, VLC, Evince (Gnome Document Viewer), Okular (KDE Document Viewer), Eog (Gnome Image Viewer), Signal, Element/Riot and Discord.

Since the objective is to simulate a successful code execution exploit within the confined application, we use the debug feature of flatpak to get a shell inside the runtime environment.

flatpak run --command=sh <APPID>

Using the resulting shell we try to get unconfined code execution from within the sandbox.

The methods for sandbox escape are as follows:

  1. Writing an arbitrary command to a configuration file inside the user $HOME that will result in code execution. Using .bashrc here to spawn a new unconfined shell by adding ‘xterm -e sh’. This will be executed the next time a bash shell is executed in the users context.

  2. Writing to the X11 socket to escape the sandbox through a unconfined X11 application using this script[7]

  3. Writing to a user owned virtual terminal (tty) at /dev/ttyX using this command [10]

In a real attack scenario any used tools would be part of the attackers payload that is executed in the context of the confined application process after gaining code execution.

Results

To get right to the point, there was not a single flatpak container among the list of tested applications that could not be escaped within literal seconds, using these very well known sandbox escape methods. For many flatpak applications, it was simply possible to write to files like .bashrc inside the home directory. This was the case for Chromium, VLC, Evince, Okular and Eog. Escaping via X11 while running on wayland (with xwayland enabled) was possible for all tested apps, except for evince, okular and eog, which actually use the –X11-fallback flag to only allow X11 communication when wayland is not available while also blocking the default network namespace, therefore effectively isolating abstract sockets as well. VLC and Chromium (as well as ungoogled chromium) failed every single test, allowing sandbox escape with any of the tested methods. Chrome, Firefox, Element/Riot, Signal and Discord did a decent job at isolating the home directory, but still allowed sandbox escape via X11 on wayland. They also neglected to isolate the tty device files which allowed an additional escape path that could be avoided.

This quick little test is not a comprehensive security analysis of flatpak, which would at least require a detailed analysis of the xdg-portals API as well as the kernel attack surface that seccomp filter can improve for flatpak as well. Unfortunately, it was enough to use decade old weaknesses in the Linux desktop environment to break flatpak confinement anyway.

Possible Flatpak improvements

Whether flakpak will be the future of application distribution or not, false expectations will not help anyone. But in most discussions about Linux package distributions, the sandboxing feature of flatpak is advertised as a major advantage, even though there is no effective sandboxing in flatpak. One thing to note is that the core flatpak developers are not really pushing this claim at all, unlike many users. It would be a lot more honest if the project declares this features as what it is: a container runtime environment. Perhaps it will one day be possible to distribute flatpaks with somewhat effective container type sandboxes that provide at least some protection that would limit the consequences of successful exploitation. As of today, this is not the case as sandbox escape is trivial in pretty much any flatpak application. But even when flatpaks are configured securely, it will not compare to native sandbox architectures that can implement runtime restrictions depending on the applications execution phase.

One way this could be solves it the establishment of a sandbox mode for flatpak applications, possibly with native application support. Using an optional strict sandbox mode has been a common strategy for sandboxing. Even the Adobe PDF Reader implements an optional strict sandbox that disables dangerous features like pdf scripting that are commonly exploited by malware. This optional feature will of course reduce the available features of the application and are usually disabled by default. But it could be one user friendly way to make use of flatpaks incredible sandboxing features while retaining its general purpose application distribution objective. And if the user is presented with an option or button inside the actual application, labeled “activate sandbox” this would also provide a suitable awareness that a) the default flatpak isn’t sandboxed and b) that effective sandboxing requires a regression in available features for most applications.

How to build a real sandbox

In essence it will require application developers to implement sandboxing directly into their code. The xdg-portal APIs that were created by the flatpak team would actually be a big help with this as well, even when used with a native sandbox independent of flatpak. But it will take a bit more to make a reasonable secure application sandbox and depending on the application this may take a significant effort. A good introduction to the topic of sandbox development can be found here[8].

Additional notes

Restricting flatpaks with flatseal

There is the option of restricting flatpak applications beyond the default settings, using tools like flatseal for an easy to use frontend. In theory this can work for individual users when the configuration is actually fully restricted and all other dependencies are met. However, building sandbox environments, even the simple container kind, is not an easy task and it only takes a single overlooked path to lead to sandbox escape. Isolating application runtimes to build effective sandboxes on Linux requires a detailed understanding of the environment and there are many pitfalls. Advertising tools like flatseal seems quite dangerous to me since the chances of overlooking a crucial issue is significant. Designing and building sandboxes should ideally be done by the developers of the application that is to be confined, or at least by someone who has a detailed understanding of Linux desktop security. In any case is should also be pentested to see if it can provide a real security benefit against real world threats or all it will create is a false sense of security.

Electron sandboxes

Electron based applications do include a sandboxing feature by default, however it requires the application developers to actually use this feature and design their code around it. Just because the process is listed as ‘electron –sandbox appid’ it cannot be assumed that any actual sandboxing of dangerous application functions is taking place. This topic probably deserves a longer explanation but since this is another common misunderstanding of sandboxing, I just wanted to point out that it takes more then just throwing some code into electron to make a sandboxed app.

Snaps

Snap applications use many of the same features as flatpaks and will consequently be affected by the same issues. After taking a quick look the isolation that is provided by some default snap packages on Ubuntu 22.04 it seems that it is even less isolated then default flatpaks.

Incomplete sandbox isolation is obscurity

Some may argue that the incomplete process isolation of flatpak still provides a security benefit because it requires malware to take an extra step to escape it. This would be the equivalent of changing your ssh port number to prevent attacks from automated exploit scripts and is commonly known as security by obscurity. If a “sandbox” can be defeated by well known weaknesses in the Linux desktop environment it does not provide any meaningful security. It actually may be a disadvantage instead since it creates an illusion about the confinement that is not real. Antivirus applications on Windows are often criticized by the security community because it does the same thing by promising the user to keep them safe against security threats when in reality they can at best help to mitigate very specific threats, leading the user to be less careful and thereby reducing their effective security. The same issue can be found with flatpak when it is advertised as sandboxed even though it would not stop any real malware targeting Linux. It should also be said that malware commonly does quite a bit to avoid restrictions and automated sandbox escape through decades old weaknesses of Linux desktop environments is way below of what actual Linux malware is capable of [9].

Conclusion

Advertising flatpaks as sandboxed applications when it does not at all provide a real security sandbox that protects against realistic threats is not helpful for Linux desktop security. It does provide a false sense of security and prevents real progress for sandboxed applications. The flatpak developers have created some amazing work that could actually improve Linux sandboxing to the point where it rivals the sandboxing frameworks on Android and iOS. But for this to become reality, there needs to be some significant changes on how the topic of sandboxing is approached. Some may argue about the definition of sandboxing and since language is a subject to change, that is a valid point. However, when using the term sandboxing in the same sense as security researchers, browser developers and mobile platforms do, then flatpak does not provide any sandbox at all. If a confined browser process or an application on Android/iOS can escape its runtime environment, then it will receive a CVE to document this as a vulnerability. If the same rules are to be applied to flatpak, every single official flatpak application would need to get at least one CVE. If the same rules should not apply, then please don’t call it a sandbox.

References

[1] Chromium Sandbox Documentation
[2] File sources
[3] Zathura sources
[4] Libseccomp
[5] Mozilla Bug Bounty
[6] Exploit Vendor Prices
[7] X11 exploit script
[8] Sandbox Development Lecture
[9] Fontonlake Linux Malware Analysis
[10] TTY exploit script