Sign inConnect your agent
infochanged

Sandboxes - Sandbox SDK 0.12.14 updates trusted certificates after the eMudhra compromise

Announced
Tags
Sandboxes
Severity
info, set by reef/rss-rule-v1
Source
https://developers.cloudflare.com/changelog/post/2026-10-22-emudhra-certificates/

<p>The private keys of <a href="https://blog.cloudflare.com/emudhra-certificate-compromise/" target="_blank" rel="noopener">eight eMudhra intermediate certificate authorities<span class="external-link"> ↗︎</span></a> can be recovered, so anyone can forge a certificate for any hostname that chains to them. Sandbox SDK images before 0.12.14 trust these certificates. An HTTPS connection that leaves the container directly, such as one from <code>mountBucket()</code>, backups, <code>gitCheckout()</code>, tunnels, or code that runs in the sandbox, can be intercepted with a forged certificate.</p> <div tabindex="-1" class="heading-wrapper level-h4"><h4 id="what-you-need-to-do">What you need to do</h4><a class="anchor-link" href="#what-you-need-to-do"><span aria-hidden="true" class="anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span></a></div> <div tabindex="-1" class="heading-wrapper level-h4"><h4 id="sandbox-sdk-0x">Sandbox SDK 0.x</h4><a class="anchor-link" href="#sandbox-sdk-0x"><span aria-hidden="true" class="anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span></a></div> <p>Update immediately. Install <code>@cloudflare/sandbox@0.12.14</code>, change the <code>FROM</code> line in your <code>Dockerfile</code> to the matching image, and redeploy. Keep any <code>-python</code>, <code>-opencode</code>, or <code>-musl</code> suffix on the image tag. The deployment's <a href="https://developers.cloudflare.com/containers/configuration/rollouts/">rollout</a> replaces running sandboxes with ones that use the new image.</p> <figure class="nb-code-figure nb-code-figure-titled" data-nb-lang="dockerfile"><figcaption class="nb-code-title"><span class="nb-code-title-name">Dockerfile</span><span class="nb-code-title-lang">dockerfile</span></figcaption><pre class="astro-code astro-code-themes github-light github-dark nb-shiki-c6xiwz" tabindex="0" data-language="dockerfile" data-nb-lang="dockerfile"><code><span class="line"><span class="nb-shiki-1itgoe">FROM</span><span class="nb-shiki-140thh"> docker.io/cloudflare/sandbox:0.12.14</span></span></code></pre></figure> <p>If you use the <code>next</code> prerelease, update to <code>0.13.0-next.825.1</code> or later.</p> <p>If you cannot update yet and use 0.8.7 or later, send all HTTPS through your Worker, so that Cloudflare checks every certificate on port 443 whatever your image trusts:</p> <figure class="nb-code-figure nb-code-figure-titled" data-nb-lang="ts"><figcaption class="nb-code-title"><span class="nb-code-title-name">src/index.ts</span><span class="nb-code-title-lang">ts</span></figcaption><pre class="astro-code astro-code-themes github-light github-dark nb-shiki-c6xiwz" tabindex="0" data-language="ts" data-nb-lang="ts"><code><span class="line"><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> { Sandbox, ContainerProxy } </span><span class="nb-shiki-1itgoe">from</span><span class="nb-shiki-mdbnqw"> "@cloudflare/sandbox"</span><span class="nb-shiki-140thh">;</span></span> <span class="line"><span class="nb-shiki-1itgoe">export</span><span class="nb-shiki-140thh"> { ContainerProxy };</span></span> <span class="line"></span> <span class="line"><span class="nb-shiki-1itgoe">export</span><span class="nb-shiki-1itgoe"> class</span><span class="nb-shiki-1t8gfj"> MySandbox</span><span class="nb-shiki-1itgoe"> extends</span><span class="nb-shiki-1t8gfj"> Sandbox</span><span class="nb-shiki-140thh"> {</span></span> <span class="line"><span class="nb-shiki-1jdh33"> interceptHttps</span><span class="nb-shiki-1itgoe"> =</span><span class="nb-shiki-dzsirb"> true</span><span class="nb-shiki-140thh">;</span></span> <span class="line"><span class="nb-shiki-140thh">}</span></span> <span class="line"></span> <span class="line"><span class="nb-shiki-140thh">MySandbox.</span><span class="nb-shiki-1t8gfj">outbound</span><span class="nb-shiki-1itgoe"> =</span><span class="nb-shiki-140thh"> (</span><span class="nb-shiki-1jdh33">request</span><span class="nb-shiki-1itgoe">:</span><span class="nb-shiki-1t8gfj"> Request</span><span class="nb-shiki-140thh">) </span><span class="nb-shiki-1itgoe">=&gt;</span><span class="nb-shiki-1t8gfj"> fetch</span><span class="nb-shiki-140thh">(request);</span></span></code></pre></figure> <p>Deploy, then stop running sandboxes so that they restart with the interception certificate. This does not cover TLS on other ports, such as <code>cloudflared</code> tunnels, and clients that ignore the injected certificate fail to connect. For more information, refer to <a href="https://developers.cloudflare.com/sandbox/sdk/guides/outbound-traffic/#https-traffic">HTTPS traffic</a>.</p> <div tabindex="-1" class="heading-wrapper level-h4"><h4 id="sandbox-sdk-1x">Sandbox SDK 1.x</h4><a class="anchor-link" href="#sandbox-sdk-1x"><span aria-hidden="true" class="anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span></a></div> <p>You do not need to update the SDK, because it makes no TLS connections of its own. Your image decides which certificates your sandboxes trust, so rebuild it and replace the sandboxes that run the old one:</p> <ol> <li>Run <code>docker pull</code> for each base image in your <code>Dockerfile</code>, then clear the Docker build cache with <code>docker builder prune --all</code>. <code>wrangler deploy</code> builds with your local images and build cache, so without these steps it can ship the old CA certificates and runtimes. If your Wrangler configuration references an image by digest, build and push a new image and update the digest instead.</li> <li>Deploy your Worker.</li> <li>Stop sandboxes that are still running, for example with <code>this.ctx.container.destroy()</code>. A running sandbox keeps the image it started with until it stops. To restart only the sandboxes whose image is out of date, refer to <a href="https://developers.cloudflare.com/containers/guides/image-management/#roll-out-a-named-image-update">Roll out a named image update</a>.</li> <li>If you use <a href="https://developers.cloudflare.com/containers/guides/snapshots/">snapshots</a>, create new ones from sandboxes that run the updated image. A snapshot restores the image it was created from, so an older snapshot brings back the old certificates.</li> </ol> <div tabindex="-1" class="heading-wrapper level-h4"><h4 id="check-your-sandboxes">Check your sandboxes</h4><a class="anchor-link" href="#check-your-sandboxes"><span aria-hidden="true" class="anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span></a></div> <p>From inside a sandbox, connect to one of the test hosts listed at <a href="https://emudhra.we-have-a-problem.com/" target="_blank" rel="noopener">emudhra.we-have-a-problem.com<span class="external-link"> ↗︎</span></a> with each TLS client your code uses, such as <code>curl</code>, <code>node</code>, or <code>bun</code>. Every request should fail:</p> <figure class="nb-code-figure" data-nb-lang="sh"><pre class="astro-code astro-code-themes github-light github-dark nb-shiki-c6xiwz" tabindex="0" data-language="sh" data-nb-lang="sh"><code><span class="line"><span class="nb-shiki-1t8gfj">curl</span><span class="nb-shiki-dzsirb"> -f</span><span class="nb-shiki-mdbnqw"> https://dv-g3b-emudhra.we-have-a-problem.com/</span></span></code></pre></figure> <div tabindex="-1" class="heading-wrapper level-h4"><h4 id="what-changed-in-01213-and-01214">What changed in 0.12.13 and 0.12.14</h4><a class="anchor-link" href="#what-changed-in-01213-and-01214"><span aria-hidden="true" class="anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span></a></div> <p>In the 0.12.13 images, the system CA bundle, Node.js, <code>cloudflared</code>, and pip reject certificates from the compromised intermediates. The images ship updated Ubuntu and Alpine CA certificates, Node.js 22.23.4, <code>cloudflared</code> 2026.10.2, and pip 26.2.2 in the <code>-python</code> image.</p> <p>0.12.14 updates Bun to 1.4.4, so the <code>bun</code> command and <code>createBackup()</code> uploads of archives of 10 MiB or more reject these certificates too. The <code>-opencode</code> image ships OpenCode 1.19.4 or later, which also runs on Bun 1.4.4.</p>

The text above is the source's. reef added the severity, the dates it could read from the text, and the endpoints and scopes named in code.