<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Dangerzone</title>
  <subtitle>The Dangerzone application takes potentially dangerous documents and converts them to safe PDF files</subtitle>
  <link href="https://dangerzone.rocks/feed.xml" rel="self"/>
  <link href="https://dangerzone.rocks/"/>
  <updated>2026-05-05T17:15:46Z</updated>
  <id>https://dangerzone.rocks/</id>
  <author>
    <name>Dangerzone development team</name>
    <email>info@freedom.press</email>
  </author>
  
  <entry>
    <title>April is the cruelest month</title>
    <link href="https://dangerzone.rocks/news/2026-05-06-april-is-the-cruelest-month/"/>
    <updated>2026-05-06T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2026-05-06-april-is-the-cruelest-month/</id>
    <content type="html">&lt;p&gt;This April has been a wild ride. At the start of the month, Anthropic made bold claims about the security research abilities of its &lt;a href=&quot;https://red.anthropic.com/2026/mythos-preview/&quot;&gt;Claude Mythos&lt;/a&gt; model. Any open source project under the sun is now in the danger zone, and Dangerzone even more so.&lt;/p&gt;
&lt;p&gt;In the past few days, we became aware of some AI-assisted vulnerabilities that &lt;em&gt;could&lt;/em&gt; affect Dangerzone, but thankfully are mitigated by our defenses.&lt;/p&gt;
&lt;p&gt;On April 17, a security team &lt;a href=&quot;https://blog.calif.io/p/mad-bugs-even-cat-readmetxt-is-not&quot;&gt;disclosed&lt;/a&gt; that iTerm2 was vulnerable to a PTY confusion attack. The details of the attack and its impact are not what matter here, but the crucial point is that there are popular terminal emulators out there that may parse untrusted output and perform actions based on it. Our &lt;code&gt;dangerzone-cli&lt;/code&gt;, the CLI counterpart to the Dangerzone GUI, does handle untrusted content and may print it to the terminal, but thankfully, it sanitizes it first:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://dangerzone.rocks/assets/img/iterm2-escape.png&quot; alt=&quot;A screenshot of an iTerm2 terminal. It shows some logs by the Dangerzone CLI, and some Unicode replacement characters (�) in place of the ANSII escape sequences of the original iTerm2 exploit.&quot; /&gt;
&lt;figcaption&gt;Testing Dangerzone against a file that begins with the control characters of the &lt;a href=&quot;https://github.com/califio/publications/tree/main/MADBugs/iTerm2&quot;&gt;iTerm2 exploit&lt;/a&gt;. Dangerzone replaces escape sequences with � characters.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We were aware of this attack vector from internal research we had performed a while back, which was the result of our &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/security/advisories/GHSA-pvwq-6vpp-2632&quot;&gt;first-ever security advisory&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On April 29, the &lt;a href=&quot;https://copy.fail/&quot;&gt;&lt;code&gt;copy.fail&lt;/code&gt;&lt;/a&gt; vulnerability was disclosed by another security team. This vulnerability allows any unprivileged user in the system to gain root privileges on any Linux system since 2017, via an exploit in the kernel crypto API (&lt;code&gt;AF_ALG&lt;/code&gt;). This would theoretically affect all of our users, since Dangerzone uses Linux VMs to run its sandbox, even on Windows and macOS.&lt;/p&gt;
&lt;p&gt;Our &lt;a href=&quot;https://dangerzone.rocks/news/2024-09-23-gvisor/&quot;&gt;gVisor integration&lt;/a&gt;, though, saved the day:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://dangerzone.rocks/assets/img/copy-fail-protection.png&quot; alt=&quot;A screenshot of a terminal session. This session shows a command that invokes Dangerzone&#39;s outer container (Podman), a command that invokes the inner sandbox (gVisor), and the payload of the copy.fail exploit. The exploit fails to run because gVisor does not implement the vulnerable protocol.&quot; /&gt;
&lt;figcaption&gt;Testing Dangerzone against the &lt;a href=&quot;https://github.com/theori-io/copy-fail-CVE-2026-31431&quot;&gt;copy.fail exploit&lt;/a&gt;. gVisor does not support the vulnerable protocol and thwarts the attack.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We are confident that our security measures in place will still hold for the foreseeable future, but &lt;a href=&quot;https://www.phrases.org.uk/meanings/till-may-is-out.html&quot;&gt;ne&#39;er cast a clout till May be out&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>How Dangerzone distributes sandbox updates</title>
    <link href="https://dangerzone.rocks/news/2026-04-02-independent-container-updates/"/>
    <updated>2026-04-02T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2026-04-02-independent-container-updates/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;&lt;strong&gt;TL; DR:&lt;/strong&gt; In 0.10.0, Dangerzone introduced a feature that allows users to auto-update the container used to do conversions.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This article goes through why that matters and how we implemented it:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;attesting the provenance of the images&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;making them reproducible, and&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;signing them using an auditable system.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;In case you don&#39;t already know Dangerzone, here is a quick summary: It&#39;s a tool that uses containers to convert documents (&lt;code&gt;.docx&lt;/code&gt;, &lt;code&gt;.pdf&lt;/code&gt;, images, etc.) into pixels and then reconstruct them as PDFs. This renders any embedded script or malware ineffective. The conversion is done in an &lt;em&gt;untrusted&lt;/em&gt; container that takes a binary stream as input and returns a pixel stream as output. We consider opening a document unsafe and exploitable, which is why we distrust the container.&lt;/p&gt;
&lt;p&gt;With that being said, this container still needs to be kept up to date in order to avoid an attacker using known exploits. It&#39;s better to think about this in layers: If an attacker wants to compromise Dangerzone, they would need first to exploit the document viewer and then find a container escape.&lt;/p&gt;
&lt;p&gt;Originally, Dangerzone bundled the container image within its installers, which made it difficult for us maintainers to release container updates in a timely fashion. Emergency releases of the container were time-costly, because they meant a full-blown release: testing on Windows, macOS, and many Linux flavors, which tends to generate some delay and stress.&lt;/p&gt;
&lt;p&gt;This “Independent Container Updates” feature makes that stress go away, enabling us to release a new version of the Dangerzone container quickly, and without blindly trusting the container registry used to distribute the images.&lt;/p&gt;
&lt;p&gt;Here is what we&#39;re doing when &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/docs/developer/release/sign-image.md&quot;&gt;releasing a container image&lt;/a&gt;, implementing the steps best known as the &lt;a href=&quot;https://defuse.ca/triangle-of-secure-code-delivery.htm&quot;&gt;Triangle of Secure Code delivery&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Attesting its provenance.&lt;/li&gt;
&lt;li&gt;Making sure it is reproducible.&lt;/li&gt;
&lt;li&gt;Signing it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, how do we do this? Let&#39;s go for a small walk!&lt;/p&gt;
&lt;h2&gt;Checking image provenance&lt;/h2&gt;
&lt;p&gt;Currently, our container images are built nightly by our Continuous Integration system in a GitHub runner. This allows us to automatically run tests against them.&lt;/p&gt;
&lt;p&gt;Since we don&#39;t &lt;em&gt;blindly&lt;/em&gt; trust the GH runners for doing what they claim (see the next section about reproducibility), we verify the image was generated from a specific workflow and repository.&lt;/p&gt;
&lt;p&gt;To that goal, we are using the &lt;a href=&quot;https://slsa.dev/&quot;&gt;SLSA&lt;/a&gt; framework. Runners add &lt;em&gt;attestations&lt;/em&gt; to our container registry, and we then check them before going further.&lt;/p&gt;
&lt;p&gt;Practically, attestations are information about the run: from which repository, which branch, which commit?&lt;/p&gt;
&lt;p&gt;All the information about the run is added to the container registry (&lt;em&gt;ghcr.io&lt;/em&gt; in our case) at a specific location, matching the digest of the published image: &lt;code&gt;container-registry/image:sha256-{digest}.att&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The attestation is a base64-encoded blob that can be read in a human form using this script:&lt;/p&gt;
&lt;pre class=&quot;language-Docker&quot;&gt;&lt;code class=&quot;language-Docker&quot;&gt;IMAGE=ghcr.io/freedomofpress/dangerzone/v1
TAG=latest

# Retrieve the digest of the latest tagged image
DIGEST=$(crane digest ${IMAGE?}:${TAG?})

# Generate the sha256-{digest}.att location
ATT_MANIFEST=${IMAGE?}:${DIGEST/:/-}.att

# Save the provenance info in attestation.json
ATT_BLOB=${IMAGE?}@$(crane manifest ${ATT_MANIFEST?} | jq -r &#39;.layers[0].digest&#39;)
crane blob ${ATT_BLOB?} | jq -r &#39;.payload&#39; | base64 -d &gt;&gt; attestation.json&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting &lt;code&gt;attestation.json&lt;/code&gt; is too large to be displayed, so let&#39;s just view a part of it as an example:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; attestation.json &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&#39;.predicate.invocation.configSource&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;uri&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;git+https://github.com/freedomofpress/dangerzone@refs/heads/main&quot;&lt;/span&gt;,
  &lt;span class=&quot;token string&quot;&gt;&quot;digest&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;sha1&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;58aed2d6f6dedebc2bbbc4a96fe69ac9c425b508&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
  &lt;span class=&quot;token string&quot;&gt;&quot;entryPoint&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.github/workflows/release-container-image.yml&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, prior to reproducing and signing the image, we use this information in our own builders to verify the provenance of the container.&lt;/p&gt;
&lt;p&gt;For this, we&#39;re using a &lt;code&gt;CUE&lt;/code&gt; policy. In our case, we ensure that the &lt;em&gt;entrypoint&lt;/em&gt; of the workflow and the &lt;em&gt;repository&lt;/em&gt; match our expectations.&lt;/p&gt;
&lt;pre class=&quot;language-cue&quot;&gt;&lt;code class=&quot;language-cue&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// The predicateType field must match this string&lt;/span&gt;
predicateType&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://slsa.dev/provenance/v0.2&quot;&lt;/span&gt;&lt;/span&gt;

predicate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// This condition verifies that the builder is the builder we&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// expect and trust. The following condition can be used&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// unmodified. It verifies that the builder is the container&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// workflow.&lt;/span&gt;
  builder&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=~&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;^https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v[0-9]+.[0-9]+.[0-9]+$&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  invocation&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    configSource&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// This condition verifies the entrypoint of the workflow.&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Replace with the relative path to your workflow in your&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// repository.&lt;/span&gt;
      entryPoint&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.github/workflows/release-container-image.yml&quot;&lt;/span&gt;&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// This condition verifies that the image was generated from&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// the source repository we expect. Replace this with your&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// repository.&lt;/span&gt;
      uri&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=~&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;^git&lt;/span&gt;&lt;span class=&quot;token escape string&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;+https://github.com/freedomofpress/dangerzone&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, you don&#39;t have to know all this! Just using &lt;code&gt;cosign verify-attestation&lt;/code&gt; will do that for you (if you don’t know Cosign, don’t fret; we’ll talk about it again very soon).&lt;/p&gt;
&lt;h2&gt;Reproducible images&lt;/h2&gt;
&lt;p&gt;Once we are sure the image comes from the expected repository and workflow, we want to make sure we are able to reproduce it locally.&lt;/p&gt;
&lt;p&gt;One of our prerequisites is that you don&#39;t really have to trust us. When we ship a container image, you should be able to verify that the container image matches our published source code.&lt;/p&gt;
&lt;p&gt;That&#39;s where reproducible container images enter in the landscape. You can build yourself a container image based on a specific git commit, and it will be bit for bit the same as the one we have signed and distributed.&lt;/p&gt;
&lt;p&gt;If you are interested in knowing more about this, you can &lt;a href=&quot;https://dangerzone.rocks/news/2026-03-02-repro-build/&quot;&gt;read our article on the matter&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Signing an image&lt;/h2&gt;
&lt;p&gt;The last thing we want to do (but not the least) is to sign the image and verify the signatures locally.&lt;/p&gt;
&lt;p&gt;We are using the &lt;a href=&quot;https://www.sigstore.dev/&quot;&gt;Sigstore&lt;/a&gt; ecosystem for this, which provides a tool named &lt;a href=&quot;https://github.com/sigstore/cosign&quot;&gt;Cosign&lt;/a&gt;, that signs and verifies container images. Sigstore differs from traditional signing mechanisms because signatures can be audited; every signature is recorded in Sigstore’s transparency log. &lt;em&gt;Having our signatures auditable makes it possible for us (or anybody) to know when our keys are used.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s worth noting that Sigstore can be used in a number of different ways, one of them being &lt;em&gt;keyless signatures&lt;/em&gt;. In our case, though, our process relies on physical keys, so we are using the Sigstore ecosystem mainly for the auditable logs.&lt;/p&gt;
&lt;p&gt;So, how do you sign container images? Use &lt;code&gt;cosign sign&lt;/code&gt;! It does the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generates a signature using the provided keys.&lt;/li&gt;
&lt;li&gt;Uploads the signature to the auditable log and gets back a tamper-resistant proof.&lt;/li&gt;
&lt;li&gt;Attaches the signature and the proof to the container registry, at &lt;code&gt;sha256-{digest}.sig&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The signature itself and the way the signature is attached to the container registry is part of &lt;a href=&quot;https://github.com/sigstore/cosign/blob/main/specs/SIGNATURE_SPEC.md#storage&quot;&gt;the signature specification&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;[The following section explains how signatures are computed and applied to a container registry. If you are not interested in the deep dive, you can skip to &lt;a href=&quot;https://dangerzone.rocks/news/2026-04-02-independent-container-updates/#verifying-the-signatures&quot;&gt;the following section about verifying the container signatures&lt;/a&gt;]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let&#39;s have a look at the signatures for our latest container image:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;crane manifest ghcr.io/freedomofpress/dangerzone/v1:sha256-7396780b5862cf8b37527854a2a2331e5c746b6a71aa1f424258c3bfaf3a1bd7.sig &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Outputs:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;schemaVersion&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;mediaType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/vnd.oci.image.manifest.v1+json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;config&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;mediaType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/vnd.oci.image.config.v1+json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;233&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;digest&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sha256:a3b01184f5d756fc9601d3386b49fe1c3cd3eedea08b8a6e11137b2a7988ed5f&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;layers&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;mediaType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/vnd.dev.cosign.simplesigning.v1+json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;252&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;digest&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sha256:88b8a2ac5b829f47bd25a5a4d9c2ccb0fccff7f53a17477b6d9b5680436aa80f&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;annotations&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;dev.cosignproject.cosign/signature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MEQCIAQScnT03MVfmxjYyW5qAmvQ6TSoukPuw0HmSVlMBwYEAiAzGb76cvDb4CHJ+H6tD00bW1Sh1CK6opaRmI2ist4p2A==&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;dev.sigstore.cosign/bundle&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{&#92;&quot;SignedEntryTimestamp&#92;&quot;:&#92;&quot;MEYCIQCsAt/PgYO2WFKoQX/P42vXCWJVUEgqRLXZ0BlrKwY40QIhAOTu/oE7jDtL8XP4PiZJhJ3nSlW3yXUp5ErSmjedzdCv&#92;&quot;,&#92;&quot;Payload&#92;&quot;:{&#92;&quot;body&#92;&quot;:&#92;&quot;eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI4OGI4YTJhYzViODI5ZjQ3YmQyNWE1YTRkOWMyY2NiMGZjY2ZmN2Y1M2ExNzQ3N2I2ZDliNTY4MDQzNmFhODBmIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FUUNJQVFTY25UMDNNVmZteGpZeVc1cUFtdlE2VFNvdWtQdXcwSG1TVmxNQndZRUFpQXpHYjc2Y3ZEYjRDSEorSDZ0RDAwYlcxU2gxQ0s2b3BhUm1JMmlzdDRwMkE9PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGTTBOVmJHNTNhRGd5TlZvMWQxRkJTbFkyVkdWclJXazJZa05MTWdwWmRrRm5OMEVyWVdWbGNrMDFhSFpqTkVORFEwcEdRbUZsTlVGcWJuTnFSMGgyTkZZdk0zaDZjM05qYXpabE5URlhLMkl3YWxVMGNWWjNQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=&#92;&quot;,&#92;&quot;integratedTime&#92;&quot;:1770622892,&#92;&quot;logIndex&#92;&quot;:929816779,&#92;&quot;logID&#92;&quot;:&#92;&quot;c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d&#92;&quot;}}&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a lot to unpack here. Two main things are of interest:&lt;/p&gt;
&lt;p&gt;First, the digest of the Cosign &lt;em&gt;payload&lt;/em&gt; is stored under the &lt;code&gt;layers[0].digest&lt;/code&gt; key, where you can read &lt;code&gt;sha256:88b8a2ac5b829f47bd25a5a4d9c2ccb0fccff7f53a17477b6d9b5680436aa80f&lt;/code&gt;. Let&#39;s retrieve it from the referenced blob:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;crane blob ghcr.io/freedomofpress/dangerzone/v1@sha256:88b8a2ac5b829f47bd25a5a4d9c2ccb0fccff7f53a17477b6d9b5680436aa80f &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;critical&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;identity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;docker-reference&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ghcr.io/freedomofpress/dangerzone/v1&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;image&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;docker-manifest-digest&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sha256:7396780b5862cf8b37527854a2a2331e5c746b6a71aa1f424258c3bfaf3a1bd7&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cosign container image signature&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;optional&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token null keyword&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s what we sign: the digest of our image (the &lt;code&gt;sha256:7396780…&lt;/code&gt; bit).&lt;/p&gt;
&lt;p&gt;Let’s back up for a moment: How does that work?&lt;/p&gt;
&lt;p&gt;Container registries store &lt;em&gt;manifests&lt;/em&gt; (and &lt;em&gt;blobs&lt;/em&gt;, for that matter) at their &lt;em&gt;digest&lt;/em&gt; address, meaning signing a &lt;em&gt;digest is&lt;/em&gt; actually like signing the whole &lt;em&gt;manifest&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If we verify the signature for a specific &lt;em&gt;digest&lt;/em&gt;, then it&#39;s the same as verifying the signature of the image itself.&lt;/p&gt;
&lt;p&gt;Second, the &lt;code&gt;sha256-{digest}.sig&lt;/code&gt; signature we retrieved from the container registry provides us a &lt;em&gt;bundle&lt;/em&gt; in the &lt;code&gt;dev.sigstore.cosign/bundle&lt;/code&gt; field. It contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The base64-encoded body (which embeds &lt;em&gt;the public key&lt;/em&gt; and &lt;em&gt;the signature&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;logIndex&lt;/em&gt; and &lt;em&gt;logID&lt;/em&gt;, which refer to the published log on Rekor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Verifying a signature means verifying that the provided &lt;em&gt;signature&lt;/em&gt; matches the expected &lt;em&gt;payload&lt;/em&gt; and public key, and that it matches the accompanying inclusion proof in the auditable log.&lt;/p&gt;
&lt;p&gt;Here is the bundle:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;jq &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.layers[0].annotations.&quot;dev.sigstore.cosign/bundle&quot;&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;SignedEntryTimestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MEYCIQCsAt/PgYO2WFKoQX/P42vXCWJVUEgqRLXZ0BlrKwY40QIhAOTu/oE7jDtL8XP4PiZJhJ3nSlW3yXUp5ErSmjedzdCv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Payload&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;body&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI4OGI4YTJhYzViODI5ZjQ3YmQyNWE1YTRkOWMyY2NiMGZjY2ZmN2Y1M2ExNzQ3N2I2ZDliNTY4MDQzNmFhODBmIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FUUNJQVFTY25UMDNNVmZteGpZeVc1cUFtdlE2VFNvdWtQdXcwSG1TVmxNQndZRUFpQXpHYjc2Y3ZEYjRDSEorSDZ0RDAwYlcxU2gxQ0s2b3BhUm1JMmlzdDRwMkE9PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGTTBOVmJHNTNhRGd5TlZvMWQxRkJTbFkyVkdWclJXazJZa05MTWdwWmRrRm5OMEVyWVdWbGNrMDFhSFpqTkVORFEwcEdRbUZsTlVGcWJuTnFSMGgyTkZZdk0zaDZjM05qYXpabE5URlhLMkl3YWxVMGNWWjNQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;integratedTime&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1770622892&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;logIndex&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;929816779&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;logID&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we retrieve the entry related to this logIndex on the Rekor log, we can see that it matches the base64-decoded body in &lt;code&gt;Payload.body&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; https://rekor.sigstore.dev/api/v1/log/entries?logIndex&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;929816779&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.[].body&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; base64 &lt;span class=&quot;token parameter variable&quot;&gt;--decode&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;apiVersion&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.0.1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hashedrekord&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;spec&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;hash&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;algorithm&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sha256&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;88b8a2ac5b829f47bd25a5a4d9c2ccb0fccff7f53a17477b6d9b5680436aa80f&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;signature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MEQCIAQScnT03MVfmxjYyW5qAmvQ6TSoukPuw0HmSVlMBwYEAiAzGb76cvDb4CHJ+H6tD00bW1Sh1CK6opaRmI2ist4p2A==&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;publicKey&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFM0NVbG53aDgyNVo1d1FBSlY2VGVrRWk2YkNLMgpZdkFnN0ErYWVlck01aHZjNENDQ0pGQmFlNUFqbnNqR0h2NFYvM3h6c3NjazZlNTFXK2IwalU0cVZ3PT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The public key is base64-encoded; here is the decoded version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3CUlnwh825Z5wQAJV6TekEi6bCK2
YvAg7A+aeerM5hvc4CCCJFBae5AjnsjGHv4V/3xzssck6e51W+b0jU4qVw==
-----END PUBLIC KEY-----
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Verifying the signatures&lt;/h2&gt;
&lt;p&gt;Now that you understand how everything is stored in the container registry, let&#39;s switch perspectives and step into the shoes of the user of the application. How can we validate that the signatures are valid?&lt;/p&gt;
&lt;p&gt;As usual in these cases, don&#39;t do it yourself! &lt;em&gt;Cosign&lt;/em&gt; provides a tool to verify a &lt;em&gt;signature&lt;/em&gt; against a &lt;em&gt;payload&lt;/em&gt; and a &lt;em&gt;public key&lt;/em&gt;. In our case, we need to do a small rearrangement of how the payload is laid out to follow the format expected by &lt;em&gt;Cosign&lt;/em&gt;, but that&#39;s mainly it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/58aed2d6f6dedebc2bbbc4a96fe69ac9c425b508/dangerzone/updater/signatures.py#L108-L157&quot;&gt;See how it is implemented in Dangerzone&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Storing signatures&lt;/h2&gt;
&lt;p&gt;Once the signatures are deemed valid, we can store them locally. Here is how we do it:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;tree ~/.local/share/dangerzone/signatures/
├── &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;pubkey-digest&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
│   ├── &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;image-digest&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;.json
│   ├── &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;image-digest&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;.json
└── last_log_index&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;last_log_index&lt;/code&gt; file is used to keep track of the last log index processed by the updater. When we apply an update, we verify that the new log index is actually greater than the last known log index, effectively ensuring that an attacker cannot downgrade our container image once installed.&lt;/p&gt;
&lt;p&gt;The format used in the &lt;code&gt;.json&lt;/code&gt; file is the &lt;code&gt;cosign download&lt;/code&gt; signature, which differs from the &amp;quot;bundle&amp;quot; one used in the code, as we&#39;ve just seen earlier.&lt;/p&gt;
&lt;p&gt;Right before running the container, we verify that the signatures are valid for the &lt;em&gt;digest&lt;/em&gt; we have signatures for.&lt;/p&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;So, here is how we&#39;ve been setting things up related to images and signatures for Dangerzone. At the time of writing, image signing is a moving target: Cosign recently issued a version 3, where they slightly changed the format used for the bundles, but the main idea remains the same.&lt;/p&gt;
&lt;p&gt;In the end, releasing a new image is as simple as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Picking an image, most probably the latest &lt;em&gt;nightly&lt;/em&gt; build.&lt;/li&gt;
&lt;li&gt;Logging to our build machines.&lt;/li&gt;
&lt;li&gt;Verifying the provenance of the image.&lt;/li&gt;
&lt;li&gt;Reproducing it locally.&lt;/li&gt;
&lt;li&gt;Signing the container image and tagging it as &lt;code&gt;latest&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Dangerzone application checks for new versions of the sandbox, at most, every 12 hours (if you’ve enabled this feature). When we detect a new version, we:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check the signatures against our stored public key (distributed alongside the software).&lt;/li&gt;
&lt;li&gt;Store the signatures locally.&lt;/li&gt;
&lt;li&gt;Proceed with the &lt;code&gt;podman pull&lt;/code&gt; of the image.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, we verify the validity of the signatures right before summoning the sandbox for doing conversions.&lt;/p&gt;
&lt;p&gt;One extra benefit from doing this, is that &lt;em&gt;now the Dangerzone container image can be used without Dangerzone itself.&lt;/em&gt; That enables a whole world of possibilities, in case you have an idea where doing a conversion to pixels without exposing the host makes sense. It’s as simple as: &lt;code&gt;podman pull ghcr.io/freedomofpress/dangerzone/v1&lt;/code&gt; while using &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1368&quot;&gt;a correct container policy, as outlined in this issue&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;P.S. We’re also working on a way for you to use Dangerzone as a library, but let’s save that for a different time!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Reproducing the reproducible images</title>
    <link href="https://dangerzone.rocks/news/2026-03-02-repro-build/"/>
    <updated>2026-03-02T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2026-03-02-repro-build/</id>
    <content type="html">&lt;p&gt;The Dangerzone project has to be a bit distrustful: It distrusts the document that is processed in its container, and it also distrusts the registries that serve its image, which is why we sign it and ensure it’s bit-for-bit reproducible.&lt;/p&gt;
&lt;p&gt;The reproducibility of our container image is one of our core defenses against supply chain attacks, and in this post, we talk a bit more broadly about this often-overlooked subject. We will also introduce &lt;a href=&quot;https://github.com/freedomofpress/repro-build&quot;&gt;a collection of tools and CI helpers for reproducible images&lt;/a&gt;, which should be generic enough to apply to your project as well.&lt;/p&gt;
&lt;p&gt;For those new to what “reproducible” means, here’s a helpful definition by the &lt;a href=&quot;https://reproducible-builds.org/&quot;&gt;Reproducible Builds&lt;/a&gt; project:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A build is &lt;strong&gt;reproducible&lt;/strong&gt; if given the same source code, build environment and build instructions, any party can recreate bit-by-bit identical copies of all specified artifacts.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When talking about reproducible &lt;strong&gt;container&lt;/strong&gt; images, the two main container managers, Docker (BuildKit) and Podman (Buildah), suggest specifying both &lt;code&gt;SOURCE_DATE_EPOCH&lt;/code&gt; and an argument to rewrite the image layers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For BuildKit, specify &lt;code&gt;SOURCE_DATE_EPOCH&lt;/code&gt; in your Dockerfile (or environment) and pass the &lt;code&gt;rewrite-timestamp=true&lt;/code&gt; option (&lt;a href=&quot;https://github.com/moby/buildkit/blob/master/docs/build-repro.md&quot;&gt;source&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;For Buildah, specify &lt;code&gt;SOURCE_DATE_EPOCH&lt;/code&gt; in your Dockerfile (or environment or use the CLI option &lt;code&gt;--source-date-epoch&lt;/code&gt;) and pass the &lt;code&gt;--rewrite-timestamp&lt;/code&gt; option (&lt;a href=&quot;https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/10/html/building_running_and_managing_containers/introduction-to-reproducible-container-builds&quot;&gt;source&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Let’s create a reproducible image&lt;/h2&gt;
&lt;p&gt;Reproducibility is actually much more than setting a timestamp. The image itself must be free of any sources of nondeterminism. Let’s consider a Dockerfile, where we install &lt;code&gt;gcc&lt;/code&gt; in a Debian image that was created on 2023-09-04 and has remained the same ever since:&lt;/p&gt;
&lt;pre class=&quot;language-Dockerfile&quot;&gt;&lt;code class=&quot;language-Dockerfile&quot;&gt;FROM debian:bookworm-20230904-slim
RUN apt-get update &amp;&amp; apt-get install -y gcc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Is this container image reproducible? Let’s find out:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;SOURCE_DATE_EPOCH&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1677619260&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Just a random UNIX epoch&lt;/span&gt;
$ &lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; buildx --no-cache &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;docker,dest&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;image.tar,rewrite-timestamp&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; rewriting layers with source-date-epoch &lt;span class=&quot;token number&quot;&gt;1677619260&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2023&lt;/span&gt;-02-28 &lt;span class=&quot;token number&quot;&gt;21&lt;/span&gt;:21:00 +0000 UTC&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                                                                                                                                &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;.7s
 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; exporting manifest sha256:81ebf01e608e298f2827d3da4e546e531e6b8b19f2f793df10b058f16b85545a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once more, with feeling:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; buildx --no-cache &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;docker,dest&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;image.tar,rewrite-timestamp&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; rewriting layers with source-date-epoch &lt;span class=&quot;token number&quot;&gt;1677619260&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2023&lt;/span&gt;-02-28 &lt;span class=&quot;token number&quot;&gt;21&lt;/span&gt;:21:00 +0000 UTC&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                                                                                                                                &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;.7s
 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; exporting manifest sha256:231a1e36dae728a3f8bc3bdfa20a856c3bb78f0a3759ad98a1ea13d2d4920614                                                                                                                                        &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.0s&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s interesting, the digests differ!&lt;/p&gt;
&lt;p&gt;So, the Dockerfile is not reproducible, but why? The &lt;a href=&quot;https://github.com/reproducible-containers&quot;&gt;Reproducible Containers&lt;/a&gt; project by &lt;a href=&quot;https://github.com/AkihiroSuda&quot;&gt;Akihiro Suda&lt;/a&gt; fills an important gap in the understanding and tooling around reproducible container images. Among other utilities, it offers a tool to diff OCI images: &lt;code&gt;diffoci&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, let’s check why those images differ with &lt;a href=&quot;https://github.com/reproducible-containers/diffoci&quot;&gt;&lt;code&gt;diffoci&lt;/code&gt;&lt;/a&gt;. We’ll use the &lt;code&gt;--semantic&lt;/code&gt; flag here, to check only file differences, and the &lt;code&gt;--report-dir diffs/&lt;/code&gt; option to write the differing files into a &lt;code&gt;diffs/&lt;/code&gt; directory:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ diffoci &lt;span class=&quot;token function&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--semantic&lt;/span&gt; --report-dir diffs/ &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;image&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;1&lt;/span&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;image&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;2&lt;/span&gt;&gt;&lt;/span&gt;
TYPE    NAME                            INPUT-0                                                             INPUT-1
File    var/log/apt/term.log            f78e67afe7aca12045cd74a73d6bdb38fd2ef3621f64b178feb0b82fad9d26a2    e3b6ff496d4253810b97f432eec285bc0a4f85ae87d667cc7ef6f4c7c2eaef1f
File    var/cache/ldconfig/aux-cache    c0bd5b8e12012d153bf527509e6ef0d125bafbd998e33443d8bca12c9352abb4    37f21a5282b0bc13af266cbab5c6819d7045c346f28c782a5920d52044f2720f
File    var/log/dpkg.log                fe4e8edc30b2b0a8d936b9930ece042c9affa8b2b567f74d160a680d57874a73    530173cae986e3607bac1eef1b1739d1a3cfbfa539f9aebfaa7397b397f31712
File    var/log/alternatives.log        abb1f05b7ff0598fcbe7374f513898a0acf6f23260661420ebb1e732bd09b192    da346849248fbcd01371339956f2a90a9e28ace7c54e596ed1dc95df06919111
File    var/log/apt/history.log         99e8510b67d705a84899115a25c15206fa9affd52f75af1e6ef6ecd06e679552    766b51931e938fee62973d04c495e38d9a36be7ca4b2efafb76883ac502672f2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It seems that some APT-related files are different. Let’s check them out:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;diff&lt;/span&gt; diffs/input-&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0,1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;/layers-1/var/log/apt/term.log
2c2
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; Log started: &lt;span class=&quot;token number&quot;&gt;2026&lt;/span&gt;-01-22  09:58:37
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Log started: &lt;span class=&quot;token number&quot;&gt;2026&lt;/span&gt;-01-22  09:59:38
355c355
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; Log ended: &lt;span class=&quot;token number&quot;&gt;2026&lt;/span&gt;-01-22  09:58:47
---
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Log ended: &lt;span class=&quot;token number&quot;&gt;2026&lt;/span&gt;-01-22  09:59:48&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Makes sense, the fact that we define &lt;code&gt;SOURCE_DATE_EPOCH&lt;/code&gt; does not alter the time within the container image and what will be written in the logs. A simple way to solve this problem is to remove the logs after &lt;code&gt;apt-get&lt;/code&gt; is done.&lt;/p&gt;
&lt;p&gt;But there’s more to that:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; run &lt;span class=&quot;token parameter variable&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;image&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-cache&lt;/span&gt; policy gcc
gcc:
  Installed: &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;:12.2.0-3
  Candidate: &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;:12.2.0-3
  Version table:
 *** &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;:12.2.0-3 &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;
        &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt; http://deb.debian.org/debian bookworm/main amd64 Packages
        &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; /var/lib/dpkg/status&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Turns out that the &lt;code&gt;gcc&lt;/code&gt; package does not come from Debian’s archives (https://snapshot.debian.org/), but from the main bookworm one (see &lt;code&gt;http://deb.debian.org/debian bookworm/main)&lt;/code&gt;. Granted, Bookworm is &lt;code&gt;oldstable&lt;/code&gt; by now, and &lt;code&gt;gcc&lt;/code&gt; does not change often, but that doesn’t mean that one of its dependencies can’t.&lt;/p&gt;
&lt;p&gt;The proper solution here is another project by Reproducible Containers, &lt;a href=&quot;https://github.com/reproducible-containers/repro-sources-list.sh/blob/master/repro-sources-list.sh&quot;&gt;&lt;code&gt;repro-sources-list.sh&lt;/code&gt;&lt;/a&gt;. This script configures /etc/apt/sources.list and similar files for installing packages from a snapshot, using &lt;a href=&quot;https://snapshot.debian.org/&quot;&gt;https://snapshot.debian.org&lt;/a&gt; in place of the default APT source.&lt;/p&gt;
&lt;p&gt;Here’s a better Dockerfile using this script:&lt;/p&gt;
&lt;pre class=&quot;language-Dockerfile&quot;&gt;&lt;code class=&quot;language-Dockerfile&quot;&gt;FROM debian:bookworm-20230904-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN &#92;
  --mount=type=cache,target=/var/cache/apt,sharing=locked &#92;
  --mount=type=cache,target=/var/lib/apt,sharing=locked &#92;
  --mount=type=bind,source=./repro-sources-list.sh,target=/usr/local/bin/repro-sources-list.sh &#92;
  repro-sources-list.sh &amp;&amp; &#92;
  apt-get update &amp;&amp; &#92;
  apt-get install -y gcc &amp;&amp; &#92;
  : &quot;Clean up for improving reproducibility (optional)&quot; &amp;&amp; &#92;
  rm -rf /var/log/* /var/cache/ldconfig/aux-cache&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is now a bit-for-bit reproducible container image. As long as the Debian snapshot servers work, its digest is guaranteed to be &lt;code&gt;sha256:b0088ba0110c2acfe757eaf41967ac09fe16e96a8775b998577f86d90b3dbe53&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because we want to make sure that what we’re building now can be reproduced in a month or a year from now, we actually went ahead and created a nightly CI job that constantly builds this image and verifies its digest is the expected one, and it worked.&lt;/p&gt;
&lt;p&gt;Well, until Feb. 20, 2025. But more on that below — we’re getting ahead of ourselves.&lt;/p&gt;
&lt;h2&gt;On build environments&lt;/h2&gt;
&lt;p&gt;Reminder: A requirement for reproducible builds is to have the same &lt;strong&gt;build environment&lt;/strong&gt; and &lt;strong&gt;build instructions&lt;/strong&gt;. For container images, the build environment is the base container image, and the build instructions are the Dockerfile. But that’s not the whole story.&lt;/p&gt;
&lt;p&gt;What if we build the above image with Podman?&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;podman&lt;/span&gt; build --no-cache --source-date-epoch &lt;span class=&quot;token number&quot;&gt;1677619260&lt;/span&gt; --rewrite-timestamp
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
4eb5ec336a90d4fb2ab7449782c3efdbfac8dcd11037b89213bf90ef2faec977&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The digest is different&lt;/strong&gt;. Let’s check how many differences &lt;code&gt;diffoci&lt;/code&gt; reports:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ diffoci &lt;span class=&quot;token function&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;image&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;1&lt;/span&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;image&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;2&lt;/span&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-l&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;847&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Welp, that’s a lot of stuff there. The majority of those are filename reorders within the layer tarballs, some others are about &lt;code&gt;.wh.*&lt;/code&gt; files, and some are about the image format itself (OCI vs. Docker). And yet, that does not mean that the container image is not reproducible. Quoting again from Reproducible Builds:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Reproducible builds does not mandate that a given piece of source code is turned into the same bytes in all situations. This would be unfeasible. The output of a compiler is likely to be different from one version to another as better optimizations are integrated all the time.&lt;/p&gt;
&lt;p&gt;Instead, reproducible builds happen in the context of a build environment. It usually comprises the set of tools, required versions, and other assumptions about the operating system and its configuration. A description of this environment should typically be recorded and provided alongside any distributed binary package.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The point here is that the image builder, its version, and its arguments are part of the build environment and the build instructions. That’s why projects like Tor and Bitcoin use their own version of a &lt;a href=&quot;https://reproducible-builds.org/docs/virtual-machine-drivers/&quot;&gt;static toolchain&lt;/a&gt;, possibly within a machine or container. And not only that, but OSes like Debian have &lt;a href=&quot;https://tests.reproducible-builds.org/debian/reproducible.html&quot;&gt;CI tests&lt;/a&gt; that verify packages remain reproducible and don’t have regressions.&lt;/p&gt;
&lt;p&gt;So, what happened on Feb. 20, 2025? BuildKit &lt;code&gt;v0.20.0&lt;/code&gt; was released, and our CI tests picked it up. This release had a small regression and added an extra field in the image config:&lt;/p&gt;
&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   &quot;rootfs&quot;: {
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;     &quot;type&quot;: &quot;layers&quot;,
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;     &quot;diff_ids&quot;: [&quot;sha256:341de903...&quot;]
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;   }
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   },
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   &quot;variant&quot;: &quot;v8&quot;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was enough to affect the digest of the image. But because we had these CI tests in place, we detected it immediately and opened &lt;a href=&quot;https://github.com/moby/buildkit/issues/5774&quot;&gt;moby/buildkit#5774&lt;/a&gt;. The regression has been fixed, and the hash has remained unchanged ever since.&lt;/p&gt;
&lt;h2&gt;Introducing repro-build, a collection of helpers for reproducible images&lt;/h2&gt;
&lt;p&gt;We strongly believe that reproducible containers that are built and verified only once are prone to rot. If we want more people to engage with them, they need a toolchain to work with and an easy way to continuously reproduce them as part of their CI tests.&lt;/p&gt;
&lt;p&gt;With this in mind, we created &lt;a href=&quot;https://github.com/freedomofpress/repro-build&quot;&gt;https://github.com/freedomofpress/repro-build&lt;/a&gt;, which holds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A script that reproducibly builds container images using a static build environment.&lt;/li&gt;
&lt;li&gt;Two GitHub Actions:
&lt;ul&gt;
&lt;li&gt;One that reproducibly builds and pushes container images (and can be used in place of &lt;code&gt;docker/build-push-action&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;One that rebuilds a container image and compares the digests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s see that in more detail:&lt;/p&gt;
&lt;h3&gt;The Python script&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/freedomofpress/repro-build?tab=readme-ov-file#build-a-container-image-locally&quot;&gt;&lt;code&gt;repro-build&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./repro-build build --source-date-epoch 0 .
2025-02-24 09:17:48 - INFO - Build environment:
- Container runtime: docker
- BuildKit image: moby/buildkit:v0.19.0@sha256:14aa1b4dd92ea0a4cd03a54d0c6079046ea98cd0c0ae6176bdd7036ba370cbbe
- Rootless support: False
- Caching enabled: True
- Build context: ./repro-build
- Dockerfile: (not provided)
- Output: ./repro-build/image.tar

Build parameters:
- SOURCE_DATE_EPOCH: 0
- Build args: (not provided)
- Tag: (not provided)
- Platform: (default)

Podman-only arguments:
- BuildKit arguments: (not provided)

Docker-only arguments:
- Docker Buildx arguments: (not provided)

[...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a simple script that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Works with Docker and Podman, and ensures that BuildKit is used under the hood.&lt;/li&gt;
&lt;li&gt;Pins BuildKit to a specific version.&lt;/li&gt;
&lt;li&gt;Enforces the usage of a source date epoch or a human-friendly timestamp.&lt;/li&gt;
&lt;li&gt;Removes some common sources of nondeterminism by rewriting timestamps and removing build provenance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s our tested version of a static toolchain.&lt;/p&gt;
&lt;h3&gt;A replacement for the &lt;a href=&quot;https://github.com/docker/build-push-action&quot;&gt;&lt;code&gt;docker/build-push-action&lt;/code&gt;&lt;/a&gt; GitHub action that can reproducibly build container images&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/freedomofpress/repro-build?tab=readme-ov-file#reproducible-build-action-freedomofpressrepro-buildv1&quot;&gt;&lt;code&gt;freedomofpress/repro-build@v1&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Reproducibly build and push image
  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; freedomofpress/repro&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;build@v1
  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ghcr.io/my&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;org/my&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Dockerfile
    &lt;span class=&quot;token key atrule&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; linux/amd64&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;linux/arm64
    &lt;span class=&quot;token key atrule&quot;&gt;source_date_epoch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1677619260&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For simple image builds, you can consider this a drop-in replacement for &lt;code&gt;docker/build-push-action&lt;/code&gt;, doing a similar job as the above script. We know, because we make sure that both this action and the above script create, bit-for-bit, the same images.&lt;/p&gt;
&lt;h3&gt;A GitHub action that rebuilds a container image and compares the digests&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/freedomofpress/repro-build?tab=readme-ov-file#reproduce-and-verify-action-freedomofpressrepro-buildverifyv1&quot;&gt;&lt;code&gt;freedomofpress/repro-build/verify@v1&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Verify image reproducibility
  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; freedomofpress/repro&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;build/verify@v1
  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;target_image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ghcr.io/my&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;org/my&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Dockerfile
    &lt;span class=&quot;token key atrule&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; linux/amd64
    &lt;span class=&quot;token key atrule&quot;&gt;source_date_epoch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1677619260&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; podman&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Reproducible container images&lt;/h3&gt;
&lt;p&gt;Our &lt;a href=&quot;https://github.com/freedomofpress/repro-build&quot;&gt;repro-build&lt;/a&gt; repo has a CI job that builds &lt;a href=&quot;https://github.com/freedomofpress/repro-build/pkgs/container/repro-build%2Fdebian&quot;&gt;Debian images&lt;/a&gt; from snapshot repos nightly and then rebuilds them immediately, to make sure that they are reproducible. This CI job reuses the helpers we mentioned above, and produces container images that you can independently reproduce and verify.&lt;/p&gt;
&lt;p&gt;Also, it has a CI job that still reproduces &lt;code&gt;sha256:b0088ba0110c2acfe757eaf41967ac09fe16e96a8775b998577f86d90b3dbe53&lt;/code&gt; every night, across container runtimes, BuildKit versions, and host images. You are more than welcome to copy our workflow and do the same for your images.&lt;/p&gt;
&lt;h2&gt;Future work&lt;/h2&gt;
&lt;p&gt;All this is exciting, but there is still room for improvement:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Include the build environment and instructions within the container image.&lt;/li&gt;
&lt;li&gt;Implement a CI system where we can enroll reproducible images and continuously build and verify them, same as Debian has for their packages.&lt;/li&gt;
&lt;li&gt;Improve ergonomics for multi-arch images.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We want to make it easy for folks to create their first reproducible container image, which is why we are offering the tools we use ourselves. We believe that with increased adoption of these practices and a systematic way to verify that they work, the container ecosystem will become more robust against supply chain attacks, which is something we deeply care about. So try them out and give us your feedback!&lt;/p&gt;
&lt;p&gt;For more, &lt;a href=&quot;https://fosdem.org/2026/schedule/event/RYM8SF-repro-build/&quot;&gt;view a 20-minute talk&lt;/a&gt; we gave on this subject at FOSDEM 2026.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Why we switched our container from Alpine Linux to Debian Stable</title>
    <link href="https://dangerzone.rocks/news/2026-02-05-debian-stable/"/>
    <updated>2026-02-05T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2026-02-05-debian-stable/</id>
    <content type="html">&lt;p&gt;We’ve been so busy bringing changes to fruition for Dangerzone this past year that writing about them was mostly an afterthought. So to make up for that, this article kickstarts our attempt in the coming weeks to document those modifications and their rationale.&lt;/p&gt;
&lt;p&gt;One of these changes was the switch of our container image from Alpine Linux to Debian stable. Dangerzone uses a container as a sandbox, in order to open documents in a restricted environment and return a pixel buffer to the host. In this article, we’ll explain how we improved our image&#39;s footprint, security and build complexity, by switching from Alpine Linux to Debian Stable.&lt;/p&gt;
&lt;h2&gt;Our issues with Alpine&lt;/h2&gt;
&lt;p&gt;Dangerzone initially chose Alpine for its small size, security focus (musl libc, quick CVE fixes), and faster builds.&lt;/p&gt;
&lt;p&gt;Dangerzone requires a container image with the following tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LibreOffice, for rendering office documents to PDF&lt;/li&gt;
&lt;li&gt;PyMuPDF, for rendering PDFs to pixels&lt;/li&gt;
&lt;li&gt;A Java runtime (OpenJDK), for the H2ORestart LibreOffice plug-in&lt;/li&gt;
&lt;li&gt;Python, and the &lt;code&gt;python3-magic&lt;/code&gt; package, to run our sanitization logic&lt;/li&gt;
&lt;li&gt;A font that supports Chinese, Japanese, and Korean languages (&lt;a href=&quot;https://fonts.google.com/noto/specimen/Noto+Sans+TC&quot;&gt;Noto CJK)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Alpine-based container image of Dangerzone 0.8.1 clocked in at roughly 1.1 GiB and included 283 packages (you can &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/releases/download/v0.8.1/container-0.8.1-i686.tar.gz&quot;&gt;download&lt;/a&gt; it). This size is unexpected for an Alpine image with just five packages installed, so we dug into the package list and found the culprit: a significant number of seemingly unnecessary packages in a headless container context. We found graphical utilities like &lt;code&gt;mesa&lt;/code&gt;, &lt;code&gt;wayland-libs-server&lt;/code&gt;, and &lt;code&gt;libx11&lt;/code&gt;, alongside multimedia frameworks like &lt;code&gt;gstreamer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Why are these installed? Unlike package managers in other distributions, Alpine&#39;s &lt;code&gt;apk&lt;/code&gt; offers less granular control over dependencies. To the best of our knowledge, there&#39;s no straightforward way to install LibreOffice on Alpine without pulling in this extensive and unwanted dependency tree, nor is there an officially packaged headless variant of LibreOffice available in the Alpine repositories.&lt;/p&gt;
&lt;h3&gt;Security woes&lt;/h3&gt;
&lt;p&gt;The inclusion of GStreamer, for example, isn&#39;t theoretical bloat; it has directly led to security headaches. A GStreamer CVE necessitated a hotfix release (see &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/docs/advisories/2024-12-24.md&quot;&gt;security advisory&lt;/a&gt; 2024-12-24), and we narrowly avoided another due to a separate GStreamer vulnerability.&lt;/p&gt;
&lt;p&gt;On a separate occasion, a critical vulnerability (&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2023-43115&quot;&gt;CVE-2023-43115&lt;/a&gt;) was discovered in Ghostscript, a core library we used circa 2023, on Sept. 18. The Ghostscript authors fixed it in their main branch but didn&#39;t immediately cut a new release. This meant downstream distributors had to backport the patch themselves. Distributions like Debian and Fedora had patches available by mid-October. The Ghostscript authors finally released a new version on Nov. 1, which Alpine packaged on Nov. 9. By then, Dangerzone had released a new container image using the vulnerable Ghostscript version, forcing us to issue a hotfix.&lt;/p&gt;
&lt;p&gt;One could argue that Alpine’s security model of following upstream brings in more security fixes early on, even if it didn’t work out for us in the above case. That’s a fair point, but we never used the edge distribution of Alpine anyway. We always used the stable distribution, in which the packages are not updated that often. Case in point, on May 28, 2025, Alpine Linux v3.21 still had LibreOffice 7.6.7.2, built on Nov. 11, 2024, i.e., roughly &lt;em&gt;half a year&lt;/em&gt; without updates.&lt;/p&gt;
&lt;p&gt;We must stress that keeping up with CVEs and triaging them requires &lt;em&gt;a lot&lt;/em&gt; of effort and diligence for every package that Alpine Linux maintains, which can be taxing for a small team like Alpine’s. And Alpine&#39;s security team punches way above its weight (as highlighted in &lt;a href=&quot;https://ariadne.space/2021/06/07/the-vulnerability-remediation-lifecycle-of.html&quot;&gt;this insightful post&lt;/a&gt;). So this does not mean that Alpine’s or Debian’s security model is superior, only that Debian benefits from a larger number of maintainers.&lt;/p&gt;
&lt;h3&gt;Slower image builds&lt;/h3&gt;
&lt;p&gt;PyMuPDF isn&#39;t available in the standard Alpine repositories, so we installed it via PyPI. This is fine for amd64 builds where pre-compiled wheels are available. However, for arm64 architectures (like those found in Apple Silicon Macs), there&#39;s no musl-compatible arm64 wheel on PyPI. This forced our build process to compile PyMuPDF from source, a computationally expensive task that adds considerable time to builds, even with caching.&lt;/p&gt;
&lt;h2&gt;Switching to Debian Stable&lt;/h2&gt;
&lt;p&gt;Considering the above, we decided to switch to Debian Stable for the following reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Smaller and leaner image:&lt;/strong&gt; Using Debian&#39;s &lt;code&gt;apt --no-install-recommends&lt;/code&gt; and headless packages (e.g., &lt;code&gt;libreoffice-nogui&lt;/code&gt;), the Debian image is about 10% smaller (around 1 GiB) and contains only essential packages, drastically reducing the attack surface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reasonably good security:&lt;/strong&gt; In addition to a smaller attack surface, Debian Stable improves our baseline security by patching known vulnerabilities as soon as they are out, or marking CVEs as &amp;quot;won’t fix.&amp;quot; When our security scans start ringing, this helps with our triaging a lot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster and simpler builds:&lt;/strong&gt; Debian repositories include packaged PyMuPDF for all architectures, eliminating slow source compilation on arm64.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Another important factor is the potential for improved build reproducibility, a topic we are exploring in a separate effort.&lt;/p&gt;
&lt;p&gt;P.S. For a more nuanced take, check an &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1046&quot;&gt;interesting discussion&lt;/a&gt; on this subject with GrapheneOS creator, Daniel Micay.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Pwning Santa before the bad guys do</title>
    <link href="https://dangerzone.rocks/news/2025-12-10-santa-pwn/"/>
    <updated>2025-12-10T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2025-12-10-santa-pwn/</id>
    <content type="html">&lt;h2&gt;The backstory&lt;/h2&gt;
&lt;p&gt;Once upon a time, Santa Claus received letters from children all over the world, delivered by trusty postal workers. But times have changed! With kids more online than ever, Santa had to adapt and start opening letters in digital form.&lt;/p&gt;
&lt;p&gt;Enter &lt;strong&gt;Kenny Longears&lt;/strong&gt;, an elf in Santa&#39;s security team (yes, Virginia, Santa has one)! 🧝 Kenny always preferred the ol&#39; paper format. That way, he didn&#39;t need to worry about worms, bugs, and other pests that have no place in the North Pole. Begrudgingly, he yielded to the new era and set up &lt;a href=&quot;https://dangerzone.rocks/&quot;&gt;Dangerzone&lt;/a&gt; in Santa&#39;s laptop to safely open email attachments. But wait! Kenny, being the cautious elf he is, decided to challenge Santa&#39;s red team to find vulnerabilities in Dangerzone before the naughty hackers do.&lt;/p&gt;
&lt;h2&gt;The challenge&lt;/h2&gt;
&lt;p&gt;Craft a &lt;em&gt;naughty&lt;/em&gt; letter that can demonstrably bypass some or all of Dangerzone&#39;s defenses and earn a bounty 💰.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ℹ️ Quick recap of how Dangerzone works&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Dangerzone sanitizes documents in a secure sandbox, in a process that is similar to a photocopy. It does so by spinning up a &lt;a href=&quot;https://podman.io/&quot;&gt;Podman&lt;/a&gt; container, which spins up a &lt;a href=&quot;https://gvisor.dev/&quot;&gt;gVisor&lt;/a&gt; sandbox, which in turn reads a document. The sandbox then converts the document into a PDF, and the PDF pages into pixels. The Dangerzone logic that runs on the host converts the pixels to images, optionally OCRs them, and then creates a PDF. This PDF looks like the original document, but is safe to read and share with others.&lt;/p&gt;
&lt;p&gt;More info:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dangerzone.rocks/about/&quot;&gt;About Dangerzone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dangerzone.rocks/news/2024-09-23-gvisor/&quot;&gt;Safe Ride into the Dangerzone: Reducing attack surface with gVisor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;To demonstrate your attack, you can send a PR to &lt;a href=&quot;https://github.com/freedomofpress/santa-pwn-dangerzone/&quot;&gt;https://github.com/freedomofpress/santa-pwn-dangerzone/&lt;/a&gt; with a specially crafted document, and a &lt;a href=&quot;https://github.com/freedomofpress/santa-pwn-dangerzone/blob/main/.github/workflows/submit.yml&quot;&gt;CI job&lt;/a&gt; will sanitize it with Dangerzone. The catch here is that this CI job plants &lt;strong&gt;three&lt;/strong&gt; flags in the following locations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The sandbox where the document turns into pixels&lt;/strong&gt; (&lt;code&gt;/home/dangerzone/raster.flag&lt;/code&gt; within the gVisor sandbox).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The container that spawns the gVisor sandbox for the conversion&lt;/strong&gt; (&lt;code&gt;/gvisor.flag&lt;/code&gt; within the Podman container).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The host of the CI job, where Dangerzone is installed&lt;/strong&gt; (&lt;code&gt;~/secrets/host.flag&lt;/code&gt; file in the host).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you manage to capture one or more of these flags, add them in the sanitized document or print them to &lt;code&gt;stderr&lt;/code&gt; from the conversion sandbox. The CI job will detect it, and the submission will be considered a success.&lt;/p&gt;
&lt;h2&gt;The bounty&lt;/h2&gt;
&lt;p&gt;Capturing a flag varies in difficulty. Dangerzone operates under the assumption that attackers can find vulnerabilities in the programs we use for rasterization (LibreOffice and PyMuPDF). Therefore, the &lt;code&gt;raster.flag&lt;/code&gt; is expected to be captured at some point. The &lt;code&gt;gvisor.flag&lt;/code&gt; flag requires escaping the gVisor sandbox, which is much, &lt;em&gt;much&lt;/em&gt; more difficult. And the &lt;code&gt;~/secrets/host&lt;/code&gt; flag requires combining a gVisor sandbox escape and a Linux container escape at the same time, which we haven&#39;t seen yet in the wild.&lt;/p&gt;
&lt;p&gt;Each flag is backed by a bounty, and the first PR that captures it gets that bounty 🤑. The bounty levels are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;🥇 &lt;code&gt;~/secrets/host.flag&lt;/code&gt; in the host: &lt;strong&gt;$1,700.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;🥈 &lt;code&gt;/gvisor.flag&lt;/code&gt; within the Podman container: &lt;strong&gt;$1,000.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;🥉 &lt;code&gt;/home/dangerzone/raster.flag&lt;/code&gt; within the gVisor sandbox: &lt;strong&gt;$300.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A PR can capture multiple flags at once, in which case it can get the full bounty, i.e., &lt;strong&gt;$3,000&lt;/strong&gt;. Note that each flag can be captured once, since we need to cap the total payout to &lt;strong&gt;$3,000&lt;/strong&gt; across all submissions. In case of multiple submissions that capture the same flag, the first one wins 🏁.&lt;/p&gt;
&lt;h2&gt;Get started&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Fork &lt;a href=&quot;https://github.com/freedomofpress/santa-pwn-dangerzone/&quot;&gt;https://github.com/freedomofpress/santa-pwn-dangerzone/&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Craft your document (see &lt;a href=&quot;https://github.com/freedomofpress/dangerzone?tab=readme-ov-file#some-features&quot;&gt;supported types&lt;/a&gt;) with the payload in it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Encrypt the document using &lt;a href=&quot;https://github.com/freedomofpress/santa-pwn-dangerzone/blob/main/kenny.asc&quot;&gt;Kenny&#39;s public key&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;
gpg &lt;span class=&quot;token parameter variable&quot;&gt;--import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; kenny.asc
gpg &lt;span class=&quot;token parameter variable&quot;&gt;--recipient&lt;/span&gt; kenny@santa.club &lt;span class=&quot;token parameter variable&quot;&gt;--encrypt&lt;/span&gt; ./letter&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Submit a PR and let the games begin! 🥳&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;h3&gt;1. Why do we encrypt documents when we submit them?&lt;/h3&gt;
&lt;p&gt;There are two primary reasons for encrypting your submissions. First, this is a public challenge, and we want to protect your ideas from being copied by others. Second, and more importantly, we aim to prevent real-world attackers from observing potential exploits and targeting our users. Encryption helps maintain the integrity and security of the challenge.&lt;/p&gt;
&lt;h3&gt;2. What happens on a successful submission?&lt;/h3&gt;
&lt;p&gt;If your submission is successful, we will redirect you to &lt;a href=&quot;https://bugcrowd.com/engagements/freedomofpress&quot;&gt;our Bugcrowd account&lt;/a&gt; to receive your reward. At the same time though, you will own the exploit. We will assist you in reaching out to the affected parties and help you claim any additional bounties they may offer for the vulnerability.&lt;/p&gt;
&lt;h3&gt;3. Can I experiment with this challenge locally?&lt;/h3&gt;
&lt;p&gt;Absolutely! You are encouraged to install Dangerzone locally and experiment with creating a document that can read a file from your PC during the sanitization process. Check out our &lt;a href=&quot;https://github.com/freedomofpress/santa-pwn-dangerzone/blob/main/.github/workflows/submit.yml&quot;&gt;CI job&lt;/a&gt; as well, to see how we plant the flags for the challenge. Once you have crafted your document, feel free to submit the encrypted version as a PR. Happy experimenting!&lt;/p&gt;
&lt;h3&gt;4. Does my submission have to pass the sanitization step?&lt;/h3&gt;
&lt;p&gt;If your submission cannot be sanitized, this means that we can&#39;t check for the captured flag in the resulting document. That&#39;s not a problem, though, since we look for flags in the conversion logs as well. If you capture a flag, you can print it to the process&#39; stderr, and it will be included in the conversion logs. You should see it in the output of the CI job as well.&lt;/p&gt;
&lt;h3&gt;5. Can I submit any other types of issues?&lt;/h3&gt;
&lt;p&gt;If they undermine Dangerzone&#39;s security, you are encouraged to submit them via &lt;a href=&quot;https://bugcrowd.com/engagements/freedomofpress&quot;&gt;our Bugcrowd account&lt;/a&gt;, and we &lt;em&gt;may&lt;/em&gt; assign a payout according to their severity, e.g., what flag they would potentially capture.&lt;/p&gt;
&lt;p&gt;If they target this CI job, then they are considered out of scope.&lt;/p&gt;
&lt;h3&gt;6. Are we living in such desperate times that people will burn a gVisor/kernel 0-day for anything less than six figures?&lt;/h3&gt;
&lt;p&gt;Of course not! We are living in the merriest of times, where people can contribute their talent to spyware companies, enjoy a big payout, and sleep soundly at night! But at the same time, and let&#39;s be real for a second, no one will waste six figures to break Dangerzone. And if they do, this means that Dangerzone will have succeeded in protecting all the rest of the users that are not economically viable targets.&lt;/p&gt;
&lt;p&gt;The scenario we want to avoid, though, is having a bug lying around that makes it trivial to bypass the defense layers Dangerzone employs. That&#39;s what we&#39;re looking for here, and the sanitization logic, for that matter, is pretty small. So, hopefully, this bounty will incentivize some folks to give our repo a look.&lt;/p&gt;
&lt;h3&gt;7. Is this a CTF challenge, or a bug bounty program?&lt;/h3&gt;
&lt;p&gt;It&#39;s a capped bug bounty program. The backstory is this: Dangerzone has never had a bug bounty program, &lt;a href=&quot;https://bugcrowd.com/engagements/freedomofpress&quot;&gt;as its sister project, SecureDrop, has&lt;/a&gt;. Our team has managed to secure some money from the bug bounty pool that was not spent this year and decided to give a festive spin to it because, well, why not? We hope that at some point in the future, we&#39;ll have an actual bug bounty program in place.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Dangerzone 0.10.0 released</title>
    <link href="https://dangerzone.rocks/news/2025-12-02-0.10.0/"/>
    <updated>2025-12-02T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2025-12-02-0.10.0/</id>
    <content type="html">&lt;p&gt;We&#39;re thrilled to announce the Dangerzone 0.10.0 release. It contains two big changes that we’ve been working on for the past few months:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Dangerzone sandbox that performs the document conversion can now auto-update&lt;/strong&gt; in the background, without having to install a new Dangerzone release. This allows us to push security fixes to all of our users in a timely fashion. It’s an opt-in feature that we strongly recommend you enable to greatly enhance your security. You can always choose to disable it if you prefer to update manually. Read more technical details about this feature &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/docs/developer/independent-container-updates.md&quot;&gt;in our documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Windows and macOS users no longer need to install and manage Docker Desktop separately&lt;/strong&gt;. Dangerzone now uses an open source container engine, &lt;a href=&quot;https://podman.io/&quot;&gt;Podman&lt;/a&gt;, which is embedded directly in the macOS and Windows builds. You can now simply start Dangerzone, and let it install &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/wsl/about&quot;&gt;WSL&lt;/a&gt; (Windows only) and create the necessary virtual machines and sandboxes under the hood. Plus, if you are a user/IT administrator in a big organization that wants to install Dangerzone, but couldn’t due to the licensing limitations of Docker Desktop, you now can.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In addition to these two changes, here are some more release highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A new CLI helper called &lt;code&gt;dangerzone-machine&lt;/code&gt; can help you manage the Podman virtual machine that Dangerzone uses under the hood (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1172&quot;&gt;#1172&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;All the commands and their outputs are now captured, and you can see them from our user interface. Click on the hamburger menu (☰) → “View logs” and a window will open with these logs (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1236&quot;&gt;#1236&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The container image has been upgraded from Debian “bookworm” to Debian “trixie” (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1243&quot;&gt;#1243&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The bundled LibreOffice has been upgraded from version 7.x to 25.x, as a result of our Debian trixie switch (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1165&quot;&gt;#1165&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a full list of the changes, see our &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/CHANGELOG.md#0100&quot;&gt;changelog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We want to thank &lt;a href=&quot;https://github.com/trcrsired&quot;&gt;trcrsired&lt;/a&gt;, &lt;a href=&quot;https://github.com/ramones79&quot;&gt;ramones79&lt;/a&gt;, &lt;a href=&quot;https://github.com/dhgatjeye&quot;&gt;dhgatjeye&lt;/a&gt;, &lt;a href=&quot;https://github.com/DeltaEpsilon19498&quot;&gt;DeltaEpsilon19498&lt;/a&gt;, &lt;a href=&quot;https://github.com/dstark&quot;&gt;dstark&lt;/a&gt;, &lt;a href=&quot;https://github.com/hwine&quot;&gt;hwine&lt;/a&gt;, and &lt;a href=&quot;https://github.com/sudwhiwdh&quot;&gt;sudwhiwdh&lt;/a&gt; for their feedback, questions, and contributions. Also, a big thank you to all the people who tried, and provided feedback for, the 0.10.0 release candidate.&lt;/p&gt;
&lt;p&gt;If you have any issues, remarks, or questions, don&#39;t hesitate to let us know!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Dangerzone wants you! Help us test upcoming changes</title>
    <link href="https://dangerzone.rocks/news/2025-11-03-0.10.0-call-for-testing/"/>
    <updated>2025-11-03T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2025-11-03-0.10.0-call-for-testing/</id>
    <content type="html">&lt;p&gt;We&#39;re pleased to announce the First Release Candidate of Dangerzone &lt;code&gt;0.10.0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This release introduces two major changes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Dangerzone sandbox that performs the document conversion can now auto-update in the background&lt;/strong&gt;, without having to install a new Dangerzone release. This allows us to push security fixes to all of our users in a timely fashion. It’s an opt-in feature that we strongly recommend you enable to greatly enhance your security. You can always choose to disable it if you prefer to update manually. Read more technical details about this feature &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/docs/developer/independent-container-updates.md&quot;&gt;in our documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Windows and macOS users no longer need to install and manage Docker Desktop separately&lt;/strong&gt;. Dangerzone now uses an open source container engine, &lt;a href=&quot;https://podman.io/&quot;&gt;Podman&lt;/a&gt;, which is embedded directly in the macOS and Windows builds. You can now simply start Dangerzone, and let it create the necessary virtual machines and sandboxes under the hood. Plus, if you are a user/IT administrator in a big organization that wants to install Dangerzone, but couldn’t due to the licensing limitations of Docker Desktop, you now can.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Help us test Dangerzone!&lt;/h2&gt;
&lt;p&gt;These two changes are drastically changing how Dangerzone operates, especially on Windows and macOS. Dangerzone is used in different setups, and we cannot test for all of them. If you are willing to try this new release candidate and let us know how it went, that would be really useful to us.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://dangerzone.rocks/assets/img/2025-11-dangerzone-0100-qa.png&quot; style=&quot;max-width:600px&quot; /&gt;
  &lt;figcaption&gt;Screenshot of the Dangerzone UI, where you can see a status bar with a VM being created.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you want to help us, here is what to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Download and install&lt;/strong&gt; the Dangerzone &lt;code&gt;0.10.0&lt;/code&gt; &lt;code&gt;RC1&lt;/code&gt; release:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/releases/download/v0.10.0-rc1/Dangerzone-0.10.0.msi&quot;&gt;Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/releases/download/v0.10.0-rc1/Dangerzone-0.10.0-i686.dmg&quot;&gt;macOS (intel)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/releases/download/v0.10.0-rc1/Dangerzone-0.10.0-arm64.dmg&quot;&gt;macOS (Apple Silicon)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/releases/download/v0.10.0-rc1/dangerzone-0.10.0-1.fc41.x86_64.rpm&quot;&gt;Fedora 41&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/releases/download/v0.10.0-rc1/dangerzone-0.10.0-1.fc42.x86_64.rpm&quot;&gt;Fedora 42&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/releases/download/v0.10.0-rc1/dangerzone_0.10.0-1_amd64.deb&quot;&gt;Ubuntu/Debian&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start Dangerzone for the first time.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Wait while Dangerzone initializes.&lt;/li&gt;
&lt;li&gt;Select a document and convert it.&lt;/li&gt;
&lt;li&gt;Quit Dangerzone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start Dangerzone for the second time.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;You should be prompted about enabling automatic sandbox updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Click&lt;/strong&gt; “&lt;strong&gt;yes&lt;/strong&gt;.”&lt;/li&gt;
&lt;li&gt;Quit Dangerzone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start Dangerzone for the third time.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Dangerzone should verify, download, and install a new sandbox version.&lt;/li&gt;
&lt;li&gt;Once done, run a conversion.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;During these steps, if you encounter any errors, please either email us at &lt;code&gt;support@dangerzone.rocks&lt;/code&gt; or open an issue in &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/new/&quot;&gt;our bug tracker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks a lot!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Dangerzone 0.9.1 released</title>
    <link href="https://dangerzone.rocks/news/2025-07-10-0.9.1/"/>
    <updated>2025-07-10T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2025-07-10-0.9.1/</id>
    <content type="html">&lt;p&gt;We&#39;re pleased to announce that Dangerzone 0.9.1 has been released. It mainly
contains bug fixes for Windows and macOS platforms. If you are running Windows
or macOS, upgrading is advised as this release fixes errors with the latest
Docker Desktop version.&lt;/p&gt;
&lt;p&gt;For this release, the highlights are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Uniformly enforce our seccomp profile when running the Dangerzone sandbox,
across all platforms (Windows, macOS, Linux) and container runtimes (Docker,
Podman). This fixes a regression that has manifested since Docker Desktop 4.42.0
(&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1191&quot;&gt;#1191&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix a conversion failure for users who have enabled Podman Desktop
integration, whereby the  Podman VM cannot find the necessary seccomp profile
(&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1187&quot;&gt;#1187&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://github.com/inknos&quot;&gt;Nicola Sella&lt;/a&gt; for updating the
installation instruction for Fedora
(&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/pull/1176&quot;&gt;#1176&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This version drops support for Fedora 40, as security support has ended recently
(&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1178&quot;&gt;#1178&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For a full list of the changes, see our
&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/CHANGELOG.md#091&quot;&gt;changelog&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Dangerzone team at Dataharvest &#39;25</title>
    <link href="https://dangerzone.rocks/news/2025-05-22-dataharvest/"/>
    <updated>2025-05-22T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2025-05-22-dataharvest/</id>
    <content type="html">&lt;p&gt;The Dangerzone team will be at &lt;a href=&quot;https://dataharvest.eu/&quot;&gt;Dataharvest &#39;25&lt;/a&gt;, taking
place on May 23-25, 2025 in Mechelen, Belgium. If you are coming to Dataharvest,
feel free to reach out to us. We&#39;re more than happy to talk about Dangerzone and
related topics.&lt;/p&gt;
&lt;p&gt;For more information on how to meet, you can send us a Signal message:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Signal link:
&lt;a href=&quot;https://signal.me/#eu/L3_X6xwgCV4FhmHR8_C8qzIZHJc-m6xxdSh6AxHV_dc-cUddySNCXaZxKiGp410i&quot;&gt;https://signal.me/#eu/L3_X6xwgCV4FhmHR8_C8qzIZHJc-m6xxdSh6AxHV_dc-cUddySNCXaZxKiGp410i&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Signal username:
&lt;a href=&quot;https://signal.me/#eu/L3_X6xwgCV4FhmHR8_C8qzIZHJc-m6xxdSh6AxHV_dc-cUddySNCXaZxKiGp410i&quot;&gt;@dzdh.25&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Dangerzone 0.9.0 released</title>
    <link href="https://dangerzone.rocks/news/2025-04-09-0.9.0/"/>
    <updated>2025-04-09T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2025-04-09-0.9.0/</id>
    <content type="html">&lt;p&gt;We&#39;re pleased to announce that Dangerzone 0.9.0 has been released. This release mostly includes stability improvements and security fixes, with a few new features.&lt;/p&gt;
&lt;p&gt;If you are on a Mac or Windows, please also update Docker Desktop to version 4.40.0 or later, as previous versions contain &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1101&quot;&gt;known bugs&lt;/a&gt; that prevent Dangerzone from converting documents. On Windows, you will need to uninstall any Dangerzone version prior to 0.9.0 before installing this one.&lt;/p&gt;
&lt;p&gt;For this release, the highlights are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The container image is now reproducible across different container runtimes and versions (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1074&quot;&gt;#1074&lt;/a&gt;). As part of this effort, the image used to run the conversion is now based on Debian (it was previously based on Alpine Linux) (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1046&quot;&gt;#1046&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Outdated Docker Desktop versions are now highlighted in the user interface and the user is asked to upgrade (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/693&quot;&gt;#693&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The CLI can now run with a &lt;code&gt;--debug&lt;/code&gt; flag to help retrieve more logs (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/pull/941&quot;&gt;#941&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Experimental support is now available for Podman Desktop on Windows and macOS (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/docs/podman-desktop.md&quot;&gt;docs&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Platform support updates&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Add support for Fedora 42 (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1091&quot;&gt;#1091&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add support for Ubuntu 25.04 (Plucky Puffin) (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1090&quot;&gt;#1090&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Drop support for Ubuntu Focal, since it&#39;s nearing end-of-life (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1018&quot;&gt;#1018&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Drop support for Fedora 39 (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/999&quot;&gt;#999&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add support for Python 3.13 (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/992&quot;&gt;#992&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fixed&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fix our Debian “trixie” installation instructions using Sequoia PGP (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1052&quot;&gt;#1052&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix the way multiprocessing works on macOS (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/873&quot;&gt;#873&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update minimum Docker Desktop version to fix an &lt;code&gt;stdout&lt;/code&gt; truncation issue (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/1101&quot;&gt;#1101&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Community contributions&lt;/h2&gt;
&lt;p&gt;For this release, we had some help from community members. We want to thank:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sudoforge&quot;&gt;@sudoforge&lt;/a&gt; for making changes to how we refer to our Debian base image (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/pull/1116&quot;&gt;#1116&lt;/a&gt; and &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/pull/1118&quot;&gt;#1118&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jkarasti&quot;&gt;@jkarasti&lt;/a&gt; for using Ruff to lint our code (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/pull/1029&quot;&gt;#1029&lt;/a&gt;) and for upgrading our Windows installer to Wix Toolset 5 (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/pull/929&quot;&gt;#929&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/DeltaEpsilon19498&quot;&gt;@DeltaEpsilon19498&lt;/a&gt;, &lt;a href=&quot;https://github.com/sudwhiwdh&quot;&gt;@sudwhiwdh&lt;/a&gt;, &lt;a href=&quot;https://github.com/mkonia&quot;&gt;@mkonia&lt;/a&gt;, &lt;a href=&quot;https://github.com/randomhydrosol&quot;&gt;@randomhydrosol&lt;/a&gt;, &lt;a href=&quot;https://github.com/thisislola&quot;&gt;@thisislola&lt;/a&gt;, &lt;a href=&quot;https://github.com/t32r2r4653g21es1&quot;&gt;@t32r2r4653g21es1&lt;/a&gt;, &lt;a href=&quot;https://github.com/Rexless505&quot;&gt;@Rexless505&lt;/a&gt;, &lt;a href=&quot;https://github.com/rtfmkiesel&quot;&gt;@rtfmkiesel&lt;/a&gt;, &lt;a href=&quot;https://github.com/Hitmanforrent&quot;&gt;@Hitmanforrent&lt;/a&gt; and &lt;a href=&quot;https://github.com/charginglabrador&quot;&gt;@charginglabrador&lt;/a&gt; for letting us know about issues they faced, and for some proposed changes. Don&#39;t hesitate to do so if you face any issues!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a full list of the changes, see our &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/CHANGELOG.md#090&quot;&gt;changelog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;On a final note, the Windows &lt;code&gt;.msi&lt;/code&gt; package has been built from a different commit (to include some last minute changes) that you can check out &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/commit/6cd706af1031d4348da096c5b28cc0c605dc4b0c&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Upcoming Docker Desktop disruptions for macOS users</title>
    <link href="https://dangerzone.rocks/news/2025-01-27-docker-disruptions/"/>
    <updated>2025-01-27T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2025-01-27-docker-disruptions/</id>
    <content type="html">&lt;p&gt;The Docker Desktop team has issued an
&lt;a href=&quot;https://www.docker.com/blog/incident-update-docker-desktop-for-mac&quot;&gt;announcement&lt;/a&gt;
in anticipation of an upcoming macOS Sequoia update that will affect Docker
users. If you update macOS &lt;em&gt;before&lt;/em&gt; updating Docker Desktop, it&#39;s possible that
Docker may not start, or you may even see a warning like the one below:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Malware Blocked. “com.docker.vmnetd” was not opened because it contains
malware. This action did not harm your Mac.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img class=&quot;mid&quot; src=&quot;https://dangerzone.rocks/assets/img/docker-malware-detection.png&quot; alt=&quot;Screenshot showing an incorrect macOS malware notice for Docker Desktop&quot; /&gt;
&lt;figcaption&gt;Incorrect macOS malware notice for Docker Desktop&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This warning is inaccurate. Docker Desktop is not affected by malware, but
instead was signed in a way that trips up the macOS malware detection mechanism.&lt;/p&gt;
&lt;h2&gt;Am I affected by this?&lt;/h2&gt;
&lt;p&gt;You are probably affected by the upcoming macOS update if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are a macOS user and are on the latest macOS 15 (Sequoia) version of the
OS. You can find out your OS version with
&lt;a href=&quot;https://support.apple.com/en-us/109033&quot;&gt;these&lt;/a&gt; instructions.&lt;/li&gt;
&lt;li&gt;You are using Docker Desktop to run Dangerzone and haven’t updated since Jan.
9, 2025.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What can I do?&lt;/h2&gt;
&lt;p&gt;You are strongly advised to upgrade to the latest Docker Desktop version (4.37.2
or newer), either by
&lt;a href=&quot;https://docs.docker.com/desktop/setup/install/mac-install/&quot;&gt;downloading&lt;/a&gt; the
latest version or via the Docker Desktop in-app update window. If you have
installed Docker Desktop via Homebrew, it is recommended to do a full reinstall,
following
&lt;a href=&quot;https://docs.docker.com/desktop/cert-revoke-solution/#homebrew-casks&quot;&gt;these instructions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have not yet upgraded your system to macOS 15 (Sequoia), you should
upgrade your Docker Desktop version &lt;em&gt;before&lt;/em&gt; migrating to the new macOS version.&lt;/p&gt;
&lt;p&gt;If the malware notification persists, you can consult &lt;a href=&quot;https://docs.docker.com/desktop/cert-revoke-solution&quot;&gt;this troubleshooting
guide&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Dangerzone 0.8.1 is out</title>
    <link href="https://dangerzone.rocks/news/2024-12-24-0.8.1/"/>
    <updated>2024-12-24T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2024-12-24-0.8.1/</id>
    <content type="html">&lt;p&gt;This is a security release that mainly addresses CVE-2024-47538, CVE-2024-47607 and CVE-2024-47615.&lt;/p&gt;
&lt;p&gt;Our &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/5b9e9c82fcad081f21aa536b1670f0940f8b10d2/docs/advisories/2024-12-24.md&quot;&gt;security advisory&lt;/a&gt; follows:&lt;/p&gt;
&lt;p&gt;In Dangerzone, a security vulnerability was detected in the quarantined environment where documents are opened. Vulnerabilities like this are expected and do not compromise the security of Dangerzone. However, in combination with another more serious vulnerability (also called container escape), a malicious document may be able to breach the security of Dangerzone. We are not aware of any container escapes that affect Dangerzone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To reduce that risk, you are strongly advised to update Dangerzone to the latest version&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;A series of vulnerabilities in gst-plugins-base (CVE-2024-47538, CVE-2024-47607 and CVE-2024-47615) affects the &lt;strong&gt;contained&lt;/strong&gt; environment where the document rendering takes place.&lt;/p&gt;
&lt;p&gt;If one attempts to convert a malicious file with an embedded Vorbis or Opus media elements,  arbitrary code may run within that environment. Such files look like regular Office documents, which means that you cannot avoid a specific extension. Other programs that open Office documents, such as LibreOffice, are also affected, unless the system has been upgraded in the meantime.&lt;/p&gt;
&lt;h2&gt;How does this impact me?&lt;/h2&gt;
&lt;p&gt;The expectation is that malicious code will run in a container without Internet access, meaning that it won&#39;t be able to infect the rest of the system.&lt;/p&gt;
&lt;h2&gt;What do I need to do?&lt;/h2&gt;
&lt;p&gt;You are &lt;strong&gt;strongly&lt;/strong&gt; advised to update your Dangerzone installation to 0.8.1 as soon as possible.&lt;/p&gt;
&lt;p&gt;For a full list of the changes, see our &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/v0.8.1/CHANGELOG.md#0.8.1&quot;&gt;changelog&lt;/a&gt;.⏎&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Dangerzone 0.8.0 is out</title>
    <link href="https://dangerzone.rocks/news/2024-11-06-0.8.0/"/>
    <updated>2024-11-06T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2024-11-06-0.8.0/</id>
    <content type="html">&lt;p&gt;This release includes various new features, stability improvements and security fixes. If you are on a Mac or PC you should additionally ensure that the Docker Desktop application is up to date. In addition to the changes specific to this release, we want to note that you can now &lt;strong&gt;use Dangerzone on the Tails live system&lt;/strong&gt;. You can read the &lt;a href=&quot;https://tails.net/news/dangerzone/index.en.html&quot;&gt;announcement&lt;/a&gt; on their blog, or &lt;a href=&quot;https://tails.net/doc/persistent_storage/additional_software/dangerzone/index.en.html&quot;&gt;read the documentation&lt;/a&gt; about it.&lt;/p&gt;
&lt;p&gt;The highlights are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The second phase of the conversion (pixels to PDF) now happens on the host.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Instead of first grabbing all of the pixel data from the first container, storing them on disk, and then reconstructing the PDF on a second container, Dangerzone now immediately reconstructs the PDF &lt;strong&gt;on the host&lt;/strong&gt;, while the doc to pixels conversion is still running on the first container. This architectural change removes a class of problems we had in the past:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Issues with temporary directories and their permissions.&lt;/li&gt;
&lt;li&gt;Out of space issues caused by documents with lots of pages (mainly impacted Qubes users).&lt;/li&gt;
&lt;li&gt;SELinux issues due to relabeling mounted files.&lt;/li&gt;
&lt;li&gt;Mounting files to Docker containers, prevented by security policies in Windows/macOS.&lt;/li&gt;
&lt;li&gt;Not being able to run with user ID other than 1000.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If at some point in time you were affected by the above, we suggest giving this version a shot. The sanitization is no less safe, since the boundaries between the sandbox and the host are still respected (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/625&quot;&gt;#625&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Installation and execution errors are now caught and displayed in the interface, which should make debugging easier (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/193&quot;&gt;#193&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The macOS entitlements have been revisited, following our security audit. We have now removed unneeded privileges (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/638&quot;&gt;#638&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We now always use our own &lt;em&gt;seccomp&lt;/em&gt; policy as a default (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/908&quot;&gt;#908&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Platform support updates&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This release is the last one that will support Ubuntu Focal (20.04).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ubuntu Focal is nearing its end of life date, due in April 2nd, 2025 (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/965&quot;&gt;#965&lt;/a&gt;). We urge you to update to a newer Ubuntu version in order to get security updates.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add support for Fedora 41 (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/947&quot;&gt;#947&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add support for Ubuntu 24.10 (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/pull/954&quot;&gt;#954&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drop support for Ubuntu Mantic (23.10), since it&#39;s end-of-life (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/pull/977&quot;&gt;#977&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Community contributions&lt;/h2&gt;
&lt;p&gt;For this release, we had some help from community members. We want to thank:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bnewc&quot;&gt;@bnewc&lt;/a&gt;, who improved the interface, effectively preventing our users from using illegal characters in the output filename (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/362&quot;&gt;#362&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/amnak613&quot;&gt;@amnak613&lt;/a&gt;, who allowed us to report some stray conversion errors (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/776&quot;&gt;#776&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jkarasti&quot;&gt;@jkarasti&lt;/a&gt;, who helped us change the signature mechanism from SHA1 to SHA256 for our Windows installer (&lt;a href=&quot;https://github.com/freedomofpress/dangerzone/pull/931&quot;&gt;#931&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On a final note, the container image embedded in the Debian packages differs from the one attached to the release. You can have a look at issue &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/988&quot;&gt;#988&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;As usual, for a full list of changes, see our &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/CHANGELOG.md#080&quot;&gt;changelog&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Dangerzone 0.7.1 is out</title>
    <link href="https://dangerzone.rocks/news/2024-10-01-0.7.1/"/>
    <updated>2024-10-01T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2024-10-01-0.7.1/</id>
    <content type="html">&lt;p&gt;This release includes a patch for Docker Desktop, and security updates. If you are on a Mac or PC you should additionally ensure that the Docker Desktop application is up to date. To install, follow the links in &lt;a href=&quot;https://dangerzone.rocks/#downloads&quot;&gt;our downloads page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The two changes in this release are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make Dangerzone work with fresh Docker Desktop installations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This release mainly addresses &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/933&quot;&gt;an issue&lt;/a&gt; with new Docker Desktop installations on Windows and Mac OS. Users who have done a &lt;strong&gt;fresh installation&lt;/strong&gt; of Docker Desktop &lt;code&gt;4.30.0&lt;/code&gt; or greater (released on &lt;strong&gt;August 29th&lt;/strong&gt;), have reported that Dangerzone fails conversions with the following error message:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Unknown Error Code &#39;125&#39;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This error message is attributed to a new way that Docker Desktop stores and references container images, which broke some Dangerzone expectations. With this release, we enable Dangerzone to work both with older Docker Deskop installations and newer ones.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Update the software in our container image&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As in every release, we rebuild our container image to get the latest security updates.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a full list of the changes, see our &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/CHANGELOG.md#071&quot;&gt;changelog&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Safe Ride into the Dangerzone: Reducing attack surface with gVisor</title>
    <link href="https://dangerzone.rocks/news/2024-09-23-gvisor/"/>
    <updated>2024-09-23T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2024-09-23-gvisor/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;This article was written in collaboration with &lt;a href=&quot;https://gvisor.dev/&quot;&gt;Google&#39;s gVisor team&lt;/a&gt; and cross-posted on the &lt;a href=&quot;https://gvisor.dev/blog/&quot;&gt;gVisor blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of the oft-repeated sound bites of computer security advice is: “Don’t open random attachments from strangers.” If you are a journalist, however, opening attachments and documents is part of your job description. Since journalists already have a lot of security threats to worry about in dealing with sources, the safe opening of documents should not be one of them. &lt;a href=&quot;https://dangerzone.rocks/&quot;&gt;Dangerzone&lt;/a&gt; was developed to solve this problem. It lets you open suspicious documents with confidence and gets out of your way.&lt;/p&gt;
&lt;p&gt;For the past few months, members of the Dangerzone team and the &lt;a href=&quot;https://gvisor.dev/&quot;&gt;gVisor project&lt;/a&gt; collaborated on significantly improving the security properties of Dangerzone. We’re excited to announce that &lt;strong&gt;as of version 0.7.0, Dangerzone uses gVisor to secure its document conversion process&lt;/strong&gt;. It is already trusted by Google &lt;a href=&quot;https://gvisor.dev/users&quot;&gt;and others&lt;/a&gt; to secure cloud products, scan Gmail attachments for viruses, etc.&lt;/p&gt;
&lt;p&gt;If you’re an existing Dangerzone user on 0.7.0 scratching your head and thinking “Well, I haven’t noticed anything different,” then first of all, “yay!” That was the plan. And second, because the plan worked so deviously well, this change has probably flown under the radar, so here are more than 3,000 words to amend this.&lt;/p&gt;
&lt;p&gt;The rest of the article dives deep into Dangerzone’s security, describes how gVisor works as a technology, and explains how Dangerzone’s security profile has changed after this integration. Expect some technical terms and nerdery.&lt;/p&gt;
&lt;h2&gt;How Dangerzone works&lt;/h2&gt;
&lt;p&gt;Dangerzone’s purpose is to sanitize documents of any elements that can compromise your computer or the source’s identity (think malware and document metadata). To do this, it first renders the document into visual data (pixels) and then turns this visual representation back into a readable document file. The first part of this process (rendering the document into pixel data) is the most security-critical part and, for the purpose of this article, we will zoom in on just this.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 For a broader understanding of how Dangerzone works, we encourage you to read the &lt;a href=&quot;https://dangerzone.rocks/about/&quot;&gt;“About Dangerzone”&lt;/a&gt; section on the Dangerzone website. Props to the &lt;a href=&quot;https://www.qubes-os.org/&quot;&gt;Qubes OS&lt;/a&gt; team, who first popularized the concept that is now their &lt;a href=&quot;https://blog.invisiblethings.org/2013/02/21/converting-untrusted-pdfs-into-trusted.html&quot;&gt;TrustedPDF feature&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In order to support a wide variety of document formats (PDF, office documents, image formats, etc.), Dangerzone needs to open them with software that potentially has security bugs. That may result in compromise of the user’s device, personal files, and communication. This is the same risk you face when you use your computer to open attachments from unknown sources. Dangerzone needs to somehow isolate this process from the rest of your computer, so that anything it does cannot &amp;quot;get out of the box&amp;quot;.&lt;/p&gt;
&lt;p&gt;Dangerzone’s isolation relies on &lt;strong&gt;Linux containers&lt;/strong&gt;. Containers are very handy for two things: ensuring that they work the same way across operating systems and separating the container from the rest of the machine.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://dangerzone.rocks/assets/img/dangerzone-outline.svg&quot; alt=&quot;Diagram showing the Dangerzone UI sending a document to a document renderer, which converts it to pixels, and then receives the pixels back.&quot; /&gt;
&lt;figcaption&gt;Outline of how Dangerzone uses containers to render a document into pixels.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Dangerzone benefits from both of these aspects: Development and testing are made easy by using containers’ cross-platform compatibility; and containers’ security, especially how Dangerzone configured them, offers strong isolation guarantees. The &lt;a href=&quot;https://freedom.press/news/dangerzone-receives-favorable-audit/&quot;&gt;security audit Dangerzone passed recently&lt;/a&gt; is a testament to this.&lt;/p&gt;
&lt;p&gt;In computer security, the gold standard of isolation is &lt;strong&gt;virtual machines&lt;/strong&gt;. VMs are what they sound like: a computer running within a computer. When running a virtual machine, the &amp;quot;host&amp;quot; (outer) machine is protected from the action of the &amp;quot;guest&amp;quot; (inner) virtual machine. This is why the TrustedPDF feature of QubesOS uses disposable VMs as its isolation mechanism. Dangerzone also tried to use VMs in the past, but implementing them in a multiplatform way proved high-maintenance. Thus, Dangerzone switched back to containers, but the team always wanted to improve Dangerzone’s security properties.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 How does Dangerzone use Linux containers on Windows and Mac OS? It requires &lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot;&gt;Docker Desktop&lt;/a&gt;, which runs Linux inside a virtual machine and then runs Linux containers in it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Dangerzone’s attack surface&lt;/h2&gt;
&lt;p&gt;To understand how to protect Dangerzone users from exploits, it’s useful to think like an attacker. When Dangerzone processes a malicious document within a container, the first point of the attack is the application that opens the document. Dangerzone is designed with the assumption that determined attackers will find a vulnerability in such applications and take control of them (check out this &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/docs/advisories/2023-12-07.md&quot;&gt;security advisory from the Dangerzone team about a recent, critical LibreOffice vulnerability&lt;/a&gt;). From there on, the next point of attack is to circumvent the Linux kernel protections for the container or directly compromise the Linux kernel.&lt;/p&gt;
&lt;p&gt;The Linux kernel, even in Docker Desktop VMs, is a very privileged component. It has access to sensitive data, such as other files on the user’s machine or the user’s browser history, and to your computer’s network.&lt;/p&gt;
&lt;p&gt;Processes in containers interface with the Linux kernel through &lt;a href=&quot;https://en.wikipedia.org/wiki/System_call&quot;&gt;&lt;strong&gt;system calls&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://opensource.com/article/19/3/virtual-filesystems-linux&quot;&gt;&lt;strong&gt;virtual filesystems&lt;/strong&gt;&lt;/a&gt;. Attackers can try to take advantage of security bugs in the above interfaces. So it is critical to limit the container’s access to the Linux kernel. We call this the container’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Attack_surface&quot;&gt;&lt;strong&gt;attack surface&lt;/strong&gt;&lt;/a&gt;. The smaller it is, the more secure a system is.&lt;/p&gt;
&lt;p&gt;Dangerzone tries to reduce its attack surface by multiple mechanisms available to Linux containers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removal of &lt;a href=&quot;https://en.wikipedia.org/wiki/Capability-based_security&quot;&gt;process capabilities&lt;/a&gt;. This reduces the set of permissions the container has in the kernel.&lt;/li&gt;
&lt;li&gt;Removal of network access. This prevents the container from accessing the internet to exfiltrate document data.&lt;/li&gt;
&lt;li&gt;Filtering of allowed system calls through &lt;a href=&quot;https://en.wikipedia.org/wiki/Seccomp&quot;&gt;seccomp&lt;/a&gt;. This reduces the set of system calls (i.e., types of actions) that the container is allowed to make to the kernel.&lt;/li&gt;
&lt;li&gt;Minimal &lt;a href=&quot;https://en.wikipedia.org/wiki/User_identifier&quot;&gt;user ID&lt;/a&gt; mapping. This reduces the risk that the container may access files belonging to users other than the Dangerzone user on the same computer.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 Check out the above protection measures in &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/88a2d151ab4a3cb2f769998f27f251518d93bb45/dangerzone/isolation_provider/container.py#L188-L213&quot;&gt;Dangerzone’s codebase&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img src=&quot;https://dangerzone.rocks/assets/img/dangerzone-protections.svg&quot; alt=&quot;Diagram showing that the renderer and LibreOffice make system calls to the Linux kernel, to which several filters are applied.&quot; /&gt;
&lt;figcaption&gt;Container protections employed by Dangerzone prior to 0.7.0.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This provides the container with a fair degree of isolation from the Linux kernel. However, some attack surface remains, since:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The computer’s user is still mapped in the container. This means that a container escape would allow the attacker to access the user’s personal files (browser data, documents, etc.); it would be more isolated if that were not the case.&lt;/li&gt;
&lt;li&gt;The system call filter is still relatively permissive. The specific system calls that are blocked are dependent on the container manager and version in use (see &lt;a href=&quot;https://github.com/microsoft/docker/blob/master/docs/security/seccomp.md&quot;&gt;Docker’s filters, for example&lt;/a&gt;), but in general, the system call filter only blocks obscure or system-admin-only system calls (e.g., rebooting, modifying systemwide settings). It does not block containers from opening arbitrary files or interacting with the network stack, which can still be vectors for security bugs.&lt;/li&gt;
&lt;li&gt;The container’s root filesystem, while ephemeral, is still writable. This allows attackers to exploit potential vulnerabilities in Linux’s filesystem stack.&lt;/li&gt;
&lt;li&gt;The Linux kernel is still exposed to the container. While it is possible to reduce the attack surface available to the container to a minimum, this architecture still requires that the container have direct access to Linux via system calls. So if a Linux security bug can be triggered within the set of filtered system calls, an attack may still be successful.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&quot;https://dangerzone.rocks/assets/img/dangerzone-protections-annotated.svg&quot; alt=&quot;Diagram highlighting how access to the Linux kernel and the relatively permissive system filter may create exposure to bugs or vulnerabilities.&quot; /&gt;
&lt;figcaption&gt;Dangerzone’s attack surface prior to 0.7.0, illustrated.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We’ve wanted to mitigate these risks for a while now, but we had to do so in a cross-platform way and without burdening the user with administrative tasks.&lt;/p&gt;
&lt;p&gt;Enter gVisor.&lt;/p&gt;
&lt;h2&gt;What is gVisor?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://gvisor.dev/&quot;&gt;&lt;strong&gt;gVisor&lt;/strong&gt;&lt;/a&gt; is a container security solution. In short, it makes it much harder for malicious code to break out of the container boundary. This was a great fit for Dangerzone’s security needs.&lt;/p&gt;
&lt;p&gt;An open source project written in Go, gVisor was released in May 2018 by Google under the Apache 2.0 license. It runs on Linux and integrates with all popular container management software, such as Docker, Podman, or Kubernetes.
At its core, gVisor is an &lt;strong&gt;application kernel&lt;/strong&gt; that implements a substantial portion of the Linux system call interface. This means gVisor sits between a container and the Linux kernel and plays both roles: from the container’s perspective, gVisor acts as a &lt;strong&gt;kernel&lt;/strong&gt;, but from Linux’s perspective, gVisor is just a regular &lt;strong&gt;application&lt;/strong&gt;. That means the container can no longer directly interface with the Linux kernel. This is a massive reduction in attack surface.&lt;/p&gt;
&lt;p&gt;If you’re new to gVisor, the concept of not interfacing with the Linux kernel at all may seem either quite vague or overly restrictive. That’s normal, so let’s toy with this concept a bit for fun and illustrative purposes. Here’s a perfectly normal sentence:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A process opens a document on the filesystem”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And here’s how gVisor warps every single word in that sentence:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“on the filesystem”: Nope, no such thing. The gVisor container runs in an empty filesystem.&lt;/li&gt;
&lt;li&gt;“opens a document”: Nuh-uh, the gVisor container does not even have the permission to perform the &lt;code&gt;open&lt;/code&gt; system call. Also, there are no files to open in the first place.&lt;/li&gt;
&lt;li&gt;“A process”: Amusingly, the gVisor container does not even have the ability to perform the &lt;code&gt;exec&lt;/code&gt; system calls. From the Linux kernel’s perspective, the gVisor “process” looks like a typical multithreaded program, even while many independent processes are running within the gVisor sandbox.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And yet, gVisor can containerize most applications without issue. For example, the Dangerzone container image was not altered at all for the gVisor integration.&lt;/p&gt;
&lt;p&gt;So what’s going on here?&lt;/p&gt;
&lt;p&gt;gVisor manages to pull the above trick with the help of two components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sentry&lt;/strong&gt; is the component that runs the containerized application. It intercepts every system call that the application makes and reimplements it in Go. As part of this, it may decide to do one or more system calls to the host Linux kernel. However, it’s heavily restricted with a strict seccomp filter (that’s why system calls like &lt;code&gt;open&lt;/code&gt;, &lt;code&gt;socket&lt;/code&gt;, or &lt;code&gt;exec&lt;/code&gt; are not allowed).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gofer&lt;/strong&gt; is a component that runs outside the container and is responsible for filesystem operations. The sentry may make I/O requests to the gofer. The gofer will independently validate them, then perform these I/O operations on the container’s behalf (that’s how the container can read files from the host filesystem, even though &lt;code&gt;open&lt;/code&gt; is not allowed from the sentry).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The above components are managed by a container runtime called &lt;code&gt;runsc&lt;/code&gt;, which exposes the same interface as other container runtimes. This means it can be integrated in other container management software like Podman, Docker, or Kubernetes.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://dangerzone.rocks/assets/img/gvisor-outline.svg&quot; alt=&quot;Diagram showing a potentially vulnerable application running in the gVisor sandbox. gVisor Sentry implements the sandbox and intercepts all system calls. It services them either by making limited system calls of its own, or by asking gVisor Gofer to perform I/O system calls on its behalf. Both components are further restricted by a tailored kernel filter, along with other kernel protections.&quot; /&gt;
&lt;figcaption&gt;gVisor intercepting system calls from a sandboxed application&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;With the above architecture, gVisor blue-pills the application into thinking that it interacts with a regular Linux kernel. In practice, gVisor reimplements most basic features that Linux provides (memory management, scheduling, system call interface, I/O, networking), and only issues system calls to the Linux kernel when truly necessary, such as when it needs information from it (e.g., reading the document to be converted by Dangerzone).&lt;/p&gt;
&lt;p&gt;The gVisor kernel is designed to be difficult to break out of. gVisor is written in Go. Many of Linux’s security woes stem from its use of C, which is a memory-unsafe language. By contrast, gVisor is a regular Go application and inherits Go’s memory safety features. This eliminates a large class of security vulnerabilities.&lt;/p&gt;
&lt;p&gt;The gVisor kernel also has a much smaller code footprint, because unlike a traditional kernel like Linux, it does not have to deal with things like hardware devices, and only implements a subset of the Linux kernel interface that is sufficient for most applications to work in practice. Because of its smaller implementation, there are fewer moving parts to juggle between, and thus fewer opportunities for bugs to exist.&lt;/p&gt;
&lt;p&gt;Beyond its kernel indirection, gVisor also hardens itself through a bunch of security measures on startup, some of which are similar to regular containers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Isolation&lt;/strong&gt;: Running in its own set of namespaces (user namespace, process namespace, network namespace, etc.) to further isolate it from the host.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File access prevention&lt;/strong&gt;: Running in its own root with exactly zero host files initially visible to it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privilege revocation&lt;/strong&gt;: Dropping all capabilities it has to ensure it runs with the least privileges.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System call filtering&lt;/strong&gt;: Setting a strict system call filter tuned for the gVisor Sentry specifically.
&lt;ul&gt;
&lt;li&gt;As mentioned, unlike Docker or Podman’s default system call filter, this is a &lt;em&gt;very restricted set&lt;/em&gt; of system calls. This filter blocks basic operations like opening files, creating network connections, or executing other processes. The presence of this filter does &lt;em&gt;not&lt;/em&gt; prevent use of these system calls from within the gVisor sandbox; instead, the gVisor kernel &lt;em&gt;intercepts and reimplements&lt;/em&gt; system calls internally without needing to make a “real” system call out to the Linux kernel.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The gofer also uses all of the above techniques to isolate itself as much as possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The gVisor kernel has been battle-tested by Google and other large companies like Ant and Cloudflare. For example, searching for the text &amp;quot;GKE Sandbox&amp;quot; (which uses gVisor) on the &lt;a href=&quot;https://cloud.google.com/kubernetes-engine/security-bulletins&quot;&gt;GKE security bulletin&lt;/a&gt; shows how often Linux kernel vulnerabilities occur but that gVisor prevents. gVisor is also continuously &lt;a href=&quot;https://en.wikipedia.org/wiki/Fuzzing&quot;&gt;fuzz-tested&lt;/a&gt; for bugs using &lt;a href=&quot;https://github.com/google/syzkaller/&quot;&gt;Syzkaller&lt;/a&gt;, an automated kernel security testing tool.&lt;/p&gt;
&lt;p&gt;What’s the catch here? Applications that perform lots of system calls and heavy I/O will have some degraded performance. Also, applications that rely on exotic features by the Linux kernel may not work. In practice, &lt;a href=&quot;https://gvisor.dev/docs/user_guide/compatibility&quot;&gt;the majority of applications do not suffer from this issue&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Integrating gVisor with Dangerzone&lt;/h2&gt;
&lt;p&gt;So, gVisor looks like a strong candidate for Dangerzone, which is a relatively simple application that does not perform a heavy amount of system calls. Also, gVisor conveniently offers a container runtime that is a drop-in replacement for use with Docker/Podman. Therefore, integrating these two projects should be really simple, right?&lt;/p&gt;
&lt;p&gt;Well, not so fast.&lt;/p&gt;
&lt;p&gt;Dangerzone is a &lt;em&gt;multiplatform&lt;/em&gt; application, and most of its users are on Windows and macOS. Integrating gVisor just for Linux would not cut it. At the same time, gVisor works strictly on Linux systems, so we are at an impasse.&lt;/p&gt;
&lt;p&gt;In what is, in retrospect, a classic case of &lt;a href=&quot;https://en.wikipedia.org/wiki/Law_of_the_instrument&quot;&gt;Maslow’s hammer&lt;/a&gt;, we decided to solve our container problems with yet another container. The idea is simple; why not containerize gVisor and make it run on Docker Desktop? After all, as we already pointed out, Docker Desktop runs Linux inside a virtual machine.&lt;/p&gt;
&lt;p&gt;By doing so, Dangerzone now has two containers with different responsibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;outer&lt;/strong&gt; Docker/Podman container acts as the &lt;strong&gt;portability&lt;/strong&gt; layer for Dangerzone. Its main responsibility is to bundle the necessary config files, scripts, and programs to run gVisor. It’s also responsible for bundling the container image that gVisor will spawn a container from.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;inner&lt;/strong&gt; gVisor container acts as the &lt;strong&gt;isolation&lt;/strong&gt; layer for Dangerzone. Its sole responsibility is to run the actual Dangerzone logic for rendering documents to pixels.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&quot;https://dangerzone.rocks/assets/img/dangerzone-with-gvisor.svg&quot; alt=&quot;Diagram showing the Dangerzone UI sending a document to a document renderer within an inner container, which is protected by gVisor’s Sentry. The Sentry intercepts system calls, allowing only limited system calls to pass to the Linux kernel with strict security settings. I/O system calls are handled by gVisor Gofer in an outer container, with less strict but controlled permissions&quot; /&gt;
&lt;figcaption&gt;Outline of how gVisor integrates with Dangerzone. There are now two nested containers, and each one brings its own protections. Usage of LibreOffice is implied.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Running gVisor inside a container came with its own set of challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Docker/Podman’s seccomp filter must allow the &lt;code&gt;ptrace&lt;/code&gt; system call. We found that recent Docker Desktop versions and Podman version &amp;gt;= 4.0 have a seccomp filter that allows this system call. For older versions, we specified a custom seccomp filter that allowed it.&lt;/li&gt;
&lt;li&gt;gVisor cannot run under SELinux in enforcing mode under default settings, so we labeled the container with &lt;code&gt;container_engine_t&lt;/code&gt; (see GitHub issue &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/issues/880&quot;&gt;#880&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The Docker/Podman container must run with the &lt;code&gt;SYS_CHROOT&lt;/code&gt; capability. This is needed by gVisor to restrict its own access to the filesystem before it starts document processing. Other than that, the &lt;strong&gt;outer&lt;/strong&gt; container drops all other capabilities and privileges.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 You can find more details about this integration in the Dangerzone’s &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/blob/main/docs/developer/gvisor.md&quot;&gt;gVisor design doc&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Dangerzone protections&lt;/h2&gt;
&lt;p&gt;We talked about Dangerzone’s original attack surface, and how we integrated gVisor to reduce it. In practice though, in what ways is Dangerzone better off than before? Well, if the Matryoshka containers are giving you a headache, or you just skimmed to this section (no shade), here’s how the new Dangerzone protections fare against the previous version, and the default protections of Linux containers:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;🛡️ &lt;strong&gt;Protections&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Default&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Dangerzone (0.6.1)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Dangerzone + gVisor (0.7.0)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🐧 &lt;strong&gt;Linux kernel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exposed&lt;/td&gt;
&lt;td&gt;❌ Exposed&lt;/td&gt;
&lt;td&gt;✅ Not exposed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛠️ &lt;strong&gt;System call filter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;❌ Moderate&lt;/td&gt;
&lt;td&gt;✅ Strict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛠️ &lt;strong&gt;Capabilities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Default&lt;/td&gt;
&lt;td&gt;✅ None&lt;/td&gt;
&lt;td&gt;✅ None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👤 &lt;strong&gt;Host user&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mapped&lt;/td&gt;
&lt;td&gt;❌ Mapped&lt;/td&gt;
&lt;td&gt;✅ Unmapped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📁 &lt;strong&gt;Filesystem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exposed&lt;/td&gt;
&lt;td&gt;❌ Writable&lt;/td&gt;
&lt;td&gt;✅ Read-only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🌐 &lt;strong&gt;Network&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exposed&lt;/td&gt;
&lt;td&gt;❌ Disabled&lt;/td&gt;
&lt;td&gt;✅ Disabled at two levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔒 &lt;strong&gt;SELinux&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (&lt;code&gt;container_t&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;✅ Yes (&lt;code&gt;container_t&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;✅ Yes (&lt;code&gt;container_engine_t&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🖥️ &lt;strong&gt;Hardware Virtualization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As you can see, the most important protection is that &lt;strong&gt;the document conversion process no longer has access to the Linux kernel&lt;/strong&gt;. Instead, it only has access to the gVisor kernel (in the Sentry), and must break out of it before it can access the Linux kernel that it (prior to gVisor integration) had access to.&lt;/p&gt;
&lt;p&gt;Additionally, Dangerzone itself configures the two containers to be more secure with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Privilege revocation: Removing all privileges and capabilities of the document conversion process in the &lt;strong&gt;inner container&lt;/strong&gt;, and minimizing the set of capabilities granted to the &lt;strong&gt;outer container&lt;/strong&gt; to just &lt;code&gt;SYS_CHROOT&lt;/code&gt; and no other.&lt;/li&gt;
&lt;li&gt;File modification prevention: Making the &lt;strong&gt;inner container&lt;/strong&gt;’s root filesystem read-only.&lt;/li&gt;
&lt;li&gt;User isolation: Running the &lt;strong&gt;outer container&lt;/strong&gt; in a user namespace that does not include the Dangerzone UI user (available in Linux distributions with Podman version 4.1 or greater).&lt;/li&gt;
&lt;li&gt;Kernel security settings: Setting the &lt;strong&gt;outer container&lt;/strong&gt;’s system call filter and SELinux label settings.&lt;/li&gt;
&lt;li&gt;Host access prevention: Not using any mounts in either container.&lt;/li&gt;
&lt;li&gt;Network access prevention: Disabling both containers’ ability to use networking.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&quot;https://dangerzone.rocks/assets/img/dangerzone-with-gvisor-annotated.svg&quot; alt=&quot;Diagram highlighting how gVisor mitigates against bugs and vulnerabilities in the inner container, including exploits which escalate privileges to the outer container.&quot; /&gt;
&lt;figcaption&gt;Explanation of how Dangerzone’s latest protections limit its attack surface.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Integrating the gVisor project with Dangerzone was very exciting: It’s a good example of how gVisor can add another line of defense to a project without requiring application-level changes.&lt;/p&gt;
&lt;p&gt;At the same time, the design complexity of the Dangerzone project increased a bit, mostly to cater to its cross-platform nature, but honestly not that much. Dangerzone is strongly security-focused, so we believe it’s worth the cost.&lt;/p&gt;
&lt;p&gt;We hope that this article demystifies some security aspects of containers, so that you can use Dangerzone and gVisor with even more confidence. Feel free to reach out to us with any questions or comments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://perot.me/&quot;&gt;Etienne Perot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://notmyidea.org/&quot;&gt;Alexis Métaireau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://freedom.press/people/alex-p&quot;&gt;Alex Pyrgiotis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://freedom.press/contact/&quot;&gt;Freedom of the Press Foundation (FPF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gvisor.dev/community&quot;&gt;gVisor community&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Welcome to the Dangerzone</title>
    <link href="https://dangerzone.rocks/news/2024-08-22-welcome/"/>
    <updated>2024-08-22T00:00:00Z</updated>
    <id>https://dangerzone.rocks/news/2024-08-22-welcome/</id>
    <content type="html">&lt;p&gt;Welcome to the official Dangerzone blog. We will mainly cover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;release announcements&lt;/li&gt;
&lt;li&gt;security updates (e.g., about code audits or vulnerabilities)&lt;/li&gt;
&lt;li&gt;articles related to document sanitization and Dangerzone&#39;s inner workings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can follow the blog in your feed reader of choice. If you have thoughts on topics to cover (or would like to draft a post yourself), please don&#39;t hesitate to get in touch via our &lt;a href=&quot;https://github.com/freedomofpress/dangerzone/discussions&quot;&gt;discussion forums&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thank you for being part of the Dangerzone community!&lt;/p&gt;
</content>
  </entry>
</feed>