## File: README.md

# Dangerzone

Take potentially dangerous PDFs, office documents, or images and convert them to a safe PDF.


|  | 
|--|--|

Dangerzone works like this: You give it a document that you don't know if you can trust (for example, an email attachment). Inside of a sandbox, Dangerzone converts the document to a PDF (if it isn't already one), and then converts the PDF into raw pixel data: a huge list of RGB color values for each page. Then, outside of the sandbox, Dangerzone takes this pixel data and converts it back into a PDF.

_Read more about Dangerzone in the [official site](https://dangerzone.rocks/about/)._

## Getting started

Follow the instructions for each platform:

* [macOS](https://github.com/freedomofpress/dangerzone/blob/v0.11.0/INSTALL.md#macos)
* [Windows](https://github.com/freedomofpress/dangerzone/blob/v0.11.0/INSTALL.md#windows)
* [Ubuntu Linux](https://github.com/freedomofpress/dangerzone/blob/v0.11.0/INSTALL.md#ubuntu-debian)
* [Debian Linux](https://github.com/freedomofpress/dangerzone/blob/v0.11.0/INSTALL.md#ubuntu-debian)
* [Fedora Linux](https://github.com/freedomofpress/dangerzone/blob/v0.11.0/INSTALL.md#fedora)
* [Qubes OS (beta)](https://github.com/freedomofpress/dangerzone/blob/v0.11.0/INSTALL.md#qubes-os)
* [Tails](https://github.com/freedomofpress/dangerzone/blob/v0.11.0/INSTALL.md#tails)

You can read more about our operating system support [here](https://github.com/freedomofpress/dangerzone/blob/v0.11.0/INSTALL.md#operating-system-support).

## Some features

- Sandboxes don't have network access, so if a malicious document can compromise one, it can't phone home
- Sandboxes use [gVisor](https://gvisor.dev/), an application kernel written in Go, that implements a substantial portion of the Linux system call interface.
- Dangerzone can optionally OCR the safe PDFs it creates, so it will have a text layer again
- Dangerzone compresses the safe PDF to reduce file size
- After converting, Dangerzone lets you open the safe PDF in the PDF viewer of your choice, which allows you to open PDFs and office docs in Dangerzone by default so you never accidentally open a dangerous document

Dangerzone can convert these types of document into safe PDFs:

- PDF (`.pdf`)
- Microsoft Word (`.docx`, `.doc`)
- Microsoft Excel (`.xlsx`, `.xls`)
- Microsoft PowerPoint (`.pptx`, `.ppt`)
- ODF Text (`.odt`)
- ODF Spreadsheet (`.ods`)
- ODF Presentation (`.odp`)
- ODF Graphics (`.odg`)
- Hancom HWP (Hangul Word Processor) (`.hwp`, `.hwpx`)
  * Not supported on
    [Qubes OS](https://github.com/freedomofpress/dangerzone/issues/494)
- EPUB (`.epub`)
- Jpeg (`.jpg`, `.jpeg`)
- GIF (`.gif`)
- PNG (`.png`)
- SVG (`.svg`)
- other image formats (`.bmp`, `.pnm`, `.pbm`, `.ppm`, `.tif`, `.tiff`)

Dangerzone was inspired by [Qubes trusted PDF](https://blog.invisiblethings.org/2013/02/21/converting-untrusted-pdfs-into-trusted.html), but it works in non-Qubes operating systems. It uses Podman containers as sandboxes instead of virtual machines.

Set up a development environment by following [these instructions](/BUILD.md).

# License and Copyright

Licensed under the AGPLv3: [https://opensource.org/licenses/agpl-3.0](https://opensource.org/licenses/agpl-3.0)

```
Copyright © 2022–2024 Freedom of the Press Foundation and Dangerzone contributors
Copyright © 2020–2021 First Look Media
```

See also [THIRD_PARTY_NOTICE.md](THIRD_PARTY_NOTICE.md) for more information regarding the third-party software that Dangerzone depends on.

## See also

* [GIJN Toolbox: Cutting-Edge — and Free — Online Investigative Tools You Can Try Right Now](https://gijn.org/stories/cutting-edge-free-online-investigative-tools/)
* [When security matters: working with Qubes OS at the Guardian](https://www.theguardian.com/info/2024/apr/04/when-security-matters-working-with-qubes-os-at-the-guardian)

## FAQ

### Has Dangerzone received a security audit?

Yes, Dangerzone received its [first security audit](https://freedom.press/news/dangerzone-receives-favorable-audit/) by [Include Security](https://includesecurity.com/) in December 2023. The audit was generally favorable, as it didn't identify any high-risk findings, except for 3 low-risk and 7 informational findings.

### "I'm experiencing an issue while using Dangerzone."

Dangerzone gets updates to improve its features _and_ to fix problems. So, updating may be the simplest path to resolving the issue which brought you here. Here is how to update:

1. Check which version of Dangerzone you are currently using: run Dangerzone, then look for a series of numbers to the right of the logo within the app. The format of the numbers will look similar to `0.4.1`
2. Now find the latest available version of Dangerzone: go to the [download page](https://dangerzone.rocks/#downloads). Look for the version number displayed. The number will be using the same format as in Step 1.
3. Is the version on the Dangerzone download page higher than the version of your installed app? Go ahead and update.

### Can I run Dangerzone in an airgapped environment?

Yes, Dangerzone is designed to run in airgapped environments without any
configuration. If you want to update its container image, follow
[our instructions](docs/developer/independent-container-updates.md#Installing-image-updates-to-airgapped-environments).

### Can I use a custom runtime, such as Podman Desktop?

On Windows and macOS, Dangerzone embeds Podman, so there is no need to.

To use a different podman version, such as Podman Desktop, [follow our documentation](https://github.com/freedomofpress/dangerzone/blob/main/docs/podman-desktop.md).

---

## File: dev_scripts/README.md

# Developer scripts

This directory holds some scripts that are helpful for developing on Dangerzone.
Read the respective documentation for more details on some of the scripts.

* [`env.py`](../docs/developer/environments.md)
* [`qa.py`](../docs/developer/qa.md)

---

## File: docs/developer/doit.md

# Using the Doit Automation Tool

Developers can use the [Doit](https://pydoit.org/) automation tool to create
release artifacts. The purpose of the tool is to automate the manual release
instructions in `RELEASE.md` file. Not everything is automated yet, since we're
still experimenting with this tool. You can find our task definitions in this
repo's `dodo.py` file.

## Why Doit?

We picked Doit out of the various tools out there for the following reasons:

* **Pythonic:** The configuration file and tasks can be written in Python. Where
  applicable, it's easy to issue shell commands as well.
* **File targets:** Doit borrows the file target concept from Makefiles. Tasks
  can have file dependencies, and targets they build. This makes it easy to
  define a dependency graph for tasks.
* **Hash-based caching:** Unlike Makefiles, doit does not look at the
  modification timestamp of source/target files, to figure out if it needs to
  run them.  Instead, it hashes those files, and will run a task only if the
  hash of a file dependency has changed.
* **Parallelization:** Tasks can be run in parallel with the `-n` argument,
  which is similar to `make`'s `-j` argument.

## How to Doit?

First, enter your Poetry shell. Then, make sure that your environment is clean,
and you have ample disk space. You can run:

```bash
doit clean --dry-run  # if you want to see what would happen
doit clean  # you'll be asked to confirm that you want to clean everything
```

Finally, you can build all the release artifacts with `doit`, or a specific task
with:

```
doit <task>
```

## Tips and tricks

* You can run `doit list --all -s` to see the full list of tasks, their
  dependencies, and whether they are up to date (U) or will run (R). Note that
  certain small tasks are always configured to run.
* You can run `doit info <task>` to see which dependencies are missing.
* You can pass the following environment variables to the script, in order to
  affect some global parameters:
  - `CONTAINER_RUNTIME`: The container runtime to use. Either `podman` (default)
    or `docker`.
  - `RELEASE_DIR`: Where to store the release artifacts. Default path is
    `~/release-assets/<version>`
  - `APPLE_ID`: The Apple ID to use when signing/notarizing the macOS DMG.

---

## File: docs/developer/environments.md

# Create Dangerzone environments

The `dev_scripts/env.py` script creates environments where a user can run
Dangerzone, allows the user to run arbitrary commands in these environments, as
well as run Dangerzone (nested containerization).

It supports two types of environments:

1. Dev environment. This environment has developer tools, necessary for
   Dangerzone, baked in. Also, it mounts the Dangerzone source under
   `/home/user/dangerzone` in the container. The developer can then run
   Dangerzone from source, with `poetry run dangerzone`.
2. End-user environment. This environment has only Dangerzone installed in it
   from one of the following sources:

   - _(default)_: from the .deb/.rpm package that we have created
   - `--qa`: from https://packages-qa.freedom.press
   - `--prod`: from https://packages.freedom.press

   For convenience, it also has the Dangerzone source mounted under
   `/home/user/dangerzone`, but it lacks Poetry and other build tools. The
   developer can run Dangerzone there with `dangerzone`. This environment is the
   most vanilla Dangerzone environment, and should be closer to the end user's
   environment, than the development environment.

Each environment corresponds to a Dockerfile, which is generated on the fly. The
developer can see this Dockerfile by passing `--show-dockerfile`.

For usage information, run `./dev_scripts/env.py --help`.

## Nested containerization

As Dangerzone environments are containers, the isolation sandbox that Dangerzone create is a nested container.
This brings the following challenges:

1. Containers typically only have a subset of syscalls allowed, and sometimes
   only for specific arguments. This happens with the use of
   [seccomp filters](https://docs.docker.com/engine/security/seccomp/). For
   instance, in Docker, the `clone` syscall is limited in containers and cannot
   create new namespaces
   (https://docs.docker.com/engine/security/seccomp/#significant-syscalls-blocked-by-the-default-profile). For testing/development purposes, a seccomp filter for the external container is used to get around this limitation, with
   `--security-opt seccomp=unconfined`. This has the same effect as developing
   Dangerzone locally, so it should probably be sufficient for now.

2. While Linux supports nested namespaces, extra handling is required for nested
   user namespaces. By default, the configuration for each user namespace (see
   [`man login.defs`](https://man7.org/linux/man-pages/man5/login.defs.5.html)
   is to reserve 65536 UIDs/GIDs, starting from UID/GID 100000. This works fine
   for the first container, but can't work for the nested container, since it
   doesn't have enough UIDs/GIDs to refer to UID 100000. Our solution to this is
   to restrict the number of UIDs/GIDs allowed in the nested container to 2000,
   which should be enough to run `podman` in it.

3. Containers also restrict the capabilities (see
   [`man capabilities`](https://man7.org/linux/man-pages/man7/capabilities.7.html))
   of the processes that run in them. By default, containers do not have mount
   capabilities, since it requires `CAP_SYS_ADMIN`, which effectively
   [makes the process root](https://lwn.net/Articles/486306/) in the specific
   user namespace. In our case, we have to give the Dangerzone environment this
   capability, since it will have to mount directories in Podman containers. For
   this reason, as well as some extra things we bumped into during development,
   we pass `--privileged` when creating the Dangerzone environment, which
   includes the `CAP_SYS_ADMIN` capability.

## GUI containerization

Running a GUI app in a container is a tricky subject for multi-platform apps. In
our case, we deal specifically with Linux environments, so we can target just
this platform.

To understand how a GUI app can draw in the user's screen from within a
container, we must first understand how it does so outside the container. In
Unix-like systems, GUI apps act like
[clients to a display server](https://wayland.freedesktop.org/architecture.html).
The most common display server implementation is X11, and the runner-up is
Wayland. Both of these display servers share some common traits, mainly that
they use Unix domain sockets as a way of letting clients communicate with them.

So, this gives us the answer on how one can run a containerized GUI app; they
can simply mount the Unix Domain Socket in the container. In practice this is
more nuanced, for two reasons:

1. Wayland support is not that mature on Linux, so we need to
   [set some extra environment variables](https://github.com/mviereck/x11docker/wiki/How-to-provide-Wayland-socket-to-docker-container). To simplify things, we will target
   X11 / XWayland hosts, which are the majority of the Linux OSes out there.
2. Sharing the Unix Domain socket does not allow the client to talk to the
   display server, for security reasons. In order to allow the client, we need
   to mount a magic cookie stored in a file pointed at by the `$XAUTHORITY`
   envvar. Else, we can use `xhost`, which is considered slightly more dangerous
   for multi-user environments.

## Caching and Reproducibility

In order to build Dangerzone environments, the script uses the following inputs:

* Dev environment:
  - Distro name and version. Together, these comprise the base container image.
  - `poetry.lock` and `pyproject.toml`. Together, these comprise the build
    context.
* End-user environment:
  - Distro name and version. Together, these comprise the base container image.
  - `.deb` / `.rpm` Dangerzone package, as found under `deb_dist/` or `dist/`
    respectively.

Any change in these inputs busts the cache for the corresponding image. In
theory, this means that the Dangerzone environment for each commit can be built
reproducibly. In practice, there are some issues that we haven't covered yet:

1. The output images are:
   * Dev: `dangerzone.rocks/build/{distro_name}:{distro_version}`
   * End-user: `dangerzone.rocks/{distro_name}:{distro_version}`

   These images do not contain the commit/version of the Dangerzone source they
   got created from, so each one overrides the other.
2. The end-user environment expects a `.deb.` / `.rpm` tagged with the version
   of Dangerzone, but it doesn't insist being built from the current Dangerzone
   commit. This means that stale packages may be installed in the end-user
   environment.
3. The base images may be different in various environments, depending on when
   they where pulled.

## State

The main goal behind these Dangerzone environments is to make them immutable,
so that they do not require to be stored somewhere, but can be recreated from
their images. Any change to these environments should therefore be reflected to
their Dockerfile.

To enforce immutability, we delete the containers every time we run a command or
an interactive shell exits. This means that these environments are suitable only
for running Dangerzone commands, and not doing actual development in them
(install an editor, configure bash prompts, etc.)

The only point where we allow mutability is the directory where Podman stores
the images and stopped containers, which may be useful for developers. If this
proves to be an issue, we will reconsider.

---

## File: docs/developer/reproducibility.md

# Reproducible builds

We want to improve the transparency and auditability of our build artifacts, and
a way to achieve this is via reproducible builds. For a broader understanding of
what reproducible builds entail, check out https://reproducible-builds.org/.

Our build artifacts consist of:

- Container images (`amd64` and `arm64` architectures)
- macOS installers (for Intel and Apple Silicon CPUs)
- Windows installer
- Fedora packages (for regular Fedora distros and Qubes)
- Debian packages (for Debian and Ubuntu)

As of writing this, the following artifacts are reproducible:

- Container images (see [#1047](https://github.com/freedomofpress/dangerzone/issues/1047)). You can find a detailed documentation on reproducible containers in the [dangerzone-image repository](https://github.com/freedomofpress/dangerzone-image).
- Debian packages (`dangerzone` and `dangerzone-full`).

## Debian packages

Building the `.deb` files inside our pinned Debian Bookworm dev container
(`./dev_scripts/env.py --distro debian --version bookworm`) and via
`./install/linux/build-deb.py` produces byte-identical packages on every run,
given the same source tree and the same `share/container.tar`.

The mechanisms that make this work:

- **`SOURCE_DATE_EPOCH`** is pinned to the timestamp of the latest
  `debian/changelog` entry. `dpkg-source`, `dpkg-deb`, and `dh_builddeb` use
  this value for file mtimes inside the source tarball and the binary `.deb`,
  and for the `Date` field in `.changes` / `.dsc` files. The value is set by
  `debian/rules` (so it's correct even when invoking `dpkg-buildpackage`
  directly) and re-asserted by `install/linux/build-deb.py`.
- **Locale and timezone** are forced to `C.UTF-8` / `UTC`, so any tool that
  emits sorted output or formatted timestamps does so identically across
  machines.
- **File mtimes are clamped** to `SOURCE_DATE_EPOCH` after `dh_install`
  populates the staging trees. `install` and pybuild do not preserve
  timestamps, so without this step the embedded `data.tar` would carry the
  wall-clock time of the build.
- **The build environment is pinned** via the Debian Bookworm dev container,
  which fixes the versions of `dpkg`, `debhelper`, `pybuild`, and the Python
  interpreter that participate in the build.

### Verifying reproducibility

To confirm a `.deb` is reproducible, build it twice in clean environments and
compare the outputs:

```bash
# First build
./dev_scripts/env.py --distro debian --version bookworm run --dev bash -c \
    "cd dangerzone && ./install/linux/build-deb.py"
mv deb_dist deb_dist.first

# Clean and build again
git clean -fdx debian/ deb_dist/
./dev_scripts/env.py --distro debian --version bookworm run --dev bash -c \
    "cd dangerzone && ./install/linux/build-deb.py"

# Compare
sha256sum deb_dist.first/*.deb deb_dist/*.deb
# For a deeper diff if hashes differ:
#   diffoscope deb_dist.first/dangerzone_<ver>_amd64.deb deb_dist/dangerzone_<ver>_amd64.deb
```

The two sets of `.deb` files should have matching SHA-256 sums. If they don't,
`diffoscope` will show what diverged — common culprits are unpinned timestamps,
locale-dependent sort order, or files generated outside the staging trees.

---

## File: docs/developer/TESTING.md

# Dangerzone Testing

Dangerzone has some automated testing under `tests/`.

The following assumes that you have already setup the development environment.

## Run tests

Unit / integration tests are run with:

```bash
poetry run make test
```

---

## File: docs/developer/updates.md

# Update notifications

This design document explains how the notification mechanism for Dangerzone
updates works, what are its benefits and limitations, and what other
alternatives we have considered. It has been adapted by discussions on GitHub
issue [#189](https://github.com/freedomofpress/dangerzone/issues/189), and has
been updated to reflect the current design.

A user-facing document on how update notifications work can be found in
https://github.com/freedomofpress/dangerzone/wiki/Updates

## Design overview

A hamburger icon is visible across almost all of the Dangerzone windows, and is used to notify the users when there are new releases.

### First run

_We detect it's the first time Dangerzone runs because the
`settings["updater_last_check"] is None`._

Add the following keys in our `settings.json` file.

* `"updater_check_all": True`: Whether or not to check and apply independent container updates and check for new releases.
* `"updater_last_check": None`: The last time we checked for updates (in seconds
  from Unix epoch). None means that we haven't checked yet.
* `"updater_latest_version": "0.4.2"`: The latest version that the Dangerzone
  updater has detected. By default it's the current version.
* `"updater_latest_changelog": ""`: The latest changelog that the Dangerzone
  updater has detected. By default it's empty.
* `"updater_errors: 0`: The number of update check errors that we have
  encountered in a row.

Previously, `"updater_check"` was used to determine if we should check for new releases, and has been replaced by `"updater_check_all"` when adding support for independent container updates.

### Second run

_We detect it's the second time Dangerzone runs because
`settings["updater_check_all"] is not None and settings["updater_last_check"] is
None`._

Before starting up the main window, the user is prompted if they want to enable update checks.

### Subsequent runs

_We perform the following only if `settings["updater_check_all"] == True`._

1. Spawn a new thread so that we don't block the main window.
2. Check if we have cached information about a release (version and changelog).
   If yes, return those immediately.
3. Check if the last time we checked for new releases was less than 12 hours
   ago. In that case, skip this update check so that we don't leak telemetry
   stats to GitHub.
4. Hit the GitHub releases API and get the [latest release](https://api.github.com/repos/freedomofpress/dangerzone/releases/latest).
   Store the current time as the last check time, even if the call fails.
5. Check if the latest release matches `settings["updater_latest_version"]`. If
   yes, return an empty update report.
6. If a new update has been detected, return the version number and the
   changelog.
7. Add a green bubble in the notification icon, and a menu entry called "New
   version available".
8. Users who click on this entry will see a dialog with more info:

    * Title: "Dangerzone v0.5.0 has been released"
    * Body:

       > A new Dangerzone version been released. Please visit our [downloads page](https://dangerzone.rocks#downloads) to install this update.
       >
       > (Show changelog rendered from Markdown in a collapsible text box)
    * Buttons:
       - OK: Return

Notes:
* Any successful attempt to fetch info from GitHub will result in clearing the
  `settings["updater_errors"]` key.

### Error handling

_We trigger error handling when the updater thread encounters an error (either
due to an HTTPS failure or a Python exception) and does not complete
successfully._

1. Bump the number of errors we've encountered in a row
   (`settings["updater_errors"] += 1`)
2. Return an update report with the error we've encountered.
3. Update the hamburger menu with a red notification bubble, and add a menu
   entry called "Update error".
4. If a user clicks on this menu entry, show a dialog window:
    * Title: "Update check error"
    * Body:

       > Something went wrong while checking for Dangerzone updates:
       >
       > You are strongly advised to visit our [downloads page](https://dangerzone.rocks#downloads) and check for new updates manually, or consult [this page](https://github.com/freedomofpress/dangerzone/wiki/Updates) for common causes of errors . Alternatively, you can uncheck "Check for updates", if you are in an air-gapped environment and have another way of learning about updates.
       >
       > (Show the latest error message in a scrollable, copyable text box)

   * Buttons:
      - Close: Return

## Key Benefits

1. The above approach future-proofs Dangerzone against API changes or bugs in
   the update check process, by asking users to manually visit
   https://dangerzone.rocks.
2. If we want to draw the attention of users to immediately install a release,
   we can do so in the release body, which we will show in a pop-up window.
3. If we are aware of issues that prevent updates, we can add them in the wiki
   page that we show in the error popup. Wiki pages are not versioned, so we can
   add useful info even after a release.

## Security Considerations

Because this approach does not download binaries / auto-updates, it **does not
add any more security issues** than the existing, manual way of installing
updates. These issues have to do with a compromised/malicous GitHub service, and
are the following:

1. GitHub pages can alter the contents of our main site
   (https://dangerzone.rocks)
2. GitHub releases can serve an older, vulnerable version of Dangerzone, instead
   of a new update.
3. GitHub releases can serve a malicious binary (requires a joint operation from
   a malicious CA as well, for extra legitimacy).
4. GitHub releases can silently drop updates.
5. GitHub releases can know which users download Dangerzone updates.
6. Network attackers can know that a user has Dangerzone installed (because we ask the user to visit https://dangerzone.rocks)

A good update framework would probably defend against 1,2,3. This is not to say
that our users are currently unprotected, since 1-4 can be detected by the
general public and the developers (unless GitHub specifically targets an
individual, but that's another story).

## Usability Considerations

1. We do not have an update story for users that only use the Dangerzone CLI. A
   good assumption is that they are on Linux, so they auto-update.

## Alternatives

We researched a bit on this subject and found out that there are update
frameworks that do this job for us. While working on this issue, we decided that
integrating with one framework will certainly take a bit of work, especially
given that we target both Windows and MacOS systems. In the meantime though, we
didn't want to have releases out without including at least a notification
channel, since staying behind on updates has a huge negative impact on the
users' safety.

The update frameworks that we learned about are:

### Sparkle Project

[Sparkle project](https://sparkle-project.org) seems to be the de-facto update
framework in MacOS. Integrators in practice need to care about two things:
creating a proper `Appcast.xml` file on the server-side, and calling the Sparkle
code from the client-side. These are covered in the project's
[documentation](https://sparkle-project.org/documentation/).

The client-side part is not very straight-forward, since Sparkle is written in
Objective-C. Thankfully, there are others who have ventured into this before:
https://fman.io/blog/codesigning-and-automatic-updates-for-pyqt-apps/

The server-side part is also not very straight-forward. For integrators that use
GitHub releases (like us), this issue may be of help:
https://github.com/sparkle-project/Sparkle/issues/648

The Windows platform is not covered by Sparkle itself, but there are other
projects, such as [WinSparkle](https://winsparkle.org/), that follow a similar
approach. I see that there's a [Python library (`pywinsparkle`)](https://pypi.org/project/pywinsparkle/)
for interacting with WinSparkle, so this may alleviate some pains.

Note that the Sparkle project is not a silver bullet. Development missteps can
happen, and users can be left without updates. Here's an [example issue](https://github.com/sparkle-project/Sparkle/issues/345) that showcases this.

### The Update Framework

[The Update Framework](https://theupdateframework.io/) is a graduated CNCF
project hosted by Linux Foundation. It's based on the
[Thandy](https://chromium.googlesource.com/chromium/src.git/+/master/docs/updater/protocol_3_1.md)
updater for Tor. It's [not widely adopted](https://github.com/sparkle-project/Sparkle/issues/345), but some of its
adopters are high-profile, and it has passed security audits.

It's more of a [specification](https://github.com/sparkle-project/Sparkle/issues/345)
and less of a software project, although a well-maintained
[reference implementation](https://github.com/sparkle-project/Sparkle/issues/345)
in Python exists. Also, a [Python project (`tufup`)](https://doc.qt.io/qtinstallerframework/ifw-updates.html)
that builds upon this implementation makes it even easier to generate the
required keys and files.

Regardless of whether we use it, knowing about the [threat vectors](https://theupdateframework.io/security/) that it's protecting against is very important.

### Other Projects

* Qt has some updater framework as well: https://doc.qt.io/qtinstallerframework/ifw-updates.html
* Google Chrome has it's own updater framework: https://chromium.googlesource.com/chromium/src.git/+/master/docs/updater/protocol_3_1.md
* Keepass rolls out its own way to update: https://github.com/keepassxreboot/keepassxc/blob/develop/src/updatecheck/UpdateChecker.cpp
* [PyUpdater](https://github.com/Digital-Sapphire/PyUpdater) was another popular updater project for Python, but is now archived.

---

## File: docs/advisories/2023-10-25.md

# Security Advisory 2023-10-25

For users testing our [new Qubes integration (beta)](https://github.com/freedomofpress/dangerzone/blob/main/INSTALL.md#qubes-os), please note that our instructions were missing a configuration detail for disposable VMs which is necessary to fully harden the configuration.

These instructions apply to users who followed the setup instructions **before October 25, 2023**.

**What you need to do:** run the following command in dom0:

```bash
qvm-prefs dz-dvm default_dispvm ''
```

**Explanation**: In Qubes OS, the default template for disposable VMs is network-connected. For this reason, we instruct users to create their own disposable VM (`dz-dvm`). However, adversaries with the ability to execute commands on `dz-dvm` would also be able open new disposable VMs with the default settings. By setting the default_dispvm to "none" we prevent this bypass.