Skip to content

Bundled Deno 2.7.14 still trusts the compromised eMudhra/emSign intermediates (fixed in Deno 2.9.8) #15152

Open

Description

@danmackinlay

I have:

  • searched the issue tracker for similar issues
  • installed the latest version of Quarto CLI — I'm on 1.10.18, but 1.10.19, the 1.11.6 pre-release and main all pin the same Deno (export DENO=v2.7.14 in configuration)
  • formatted my issue following the Bug Reports guide

Bug description

Quarto bundles Deno 2.7.14, which verifies TLS against its own built-in root store.
That store still trusts the eight eMudhra/emSign intermediates whose private keys turned out to be recoverable from their public certificates (Mozilla bug 2083449, incident site).
Someone with a network position can mint certificates for any hostname from those intermediates, and Deno 2.7.14 accepts them.
The incident tracker lists Deno 2.9.8 as the fixed release.

This matters for the Quarto commands that make HTTPS connections from inside Deno, for example quarto publish, which sends publishing credentials, and quarto add / quarto use template, which download code.

Setting DENO_TLS_CA_STORE=system does not help on macOS: the bundled Deno still accepts both test endpoints.

I saw the runtime-migration plan (#15133); until that lands, would a 1.10.x patch release with Deno ≥ 2.9.8 be feasible?

Steps to reproduce

Save as probe.ts:

for (const h of ["dv-g3b-emudhra.we-have-a-problem.com", "dv-g3b-aaa-emudhra.we-have-a-problem.com"]) {
  try { const r = await fetch(`https://${h}/`); console.log(Deno.version.deno, h, "ACCEPTED", r.status); await r.body?.cancel(); }
  catch (e) { console.log(Deno.version.deno, h, "rejected", String(e).slice(0, 90)); }
}

Run it with Quarto's bundled Deno:

/Applications/quarto/bin/tools/aarch64/deno run --allow-net probe.ts
DENO_TLS_CA_STORE=system /Applications/quarto/bin/tools/aarch64/deno run --allow-net probe.ts

These are the incident site's published test endpoints; a client that is not vulnerable should reject both with a certificate error.

Actual behavior

2.7.14 dv-g3b-emudhra.we-have-a-problem.com ACCEPTED 200
2.7.14 dv-g3b-aaa-emudhra.we-have-a-problem.com ACCEPTED 200

The same with DENO_TLS_CA_STORE=system.

Expected behavior

Both connections fail certificate verification.
Deno 2.9.8 (Homebrew) rejects both endpoints on the same machine.

Your environment

  • OS: macOS 26.6.2 (Tahoe), Apple Silicon
  • Quarto 1.10.18, official .pkg installer
  • IDE: not relevant (reproduced from the terminal)

Quarto check output

Trimmed to the version section:

Quarto 1.10.18
[✓] Checking versions of quarto binary dependencies...
      Pandoc version 3.10.0: OK
      Dart Sass version 1.101.0: OK
      Deno version 2.7.14: OK
      Typst version 0.15.1: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
      Version: 1.10.18
      Path: /Applications/quarto/bin

AI assistance

For the sake of speed, I used an LLM assistant (Claude Code) to investigate this and draft the report: it ran the probes above on my machine and read Quarto's configuration across releases.
I reviewed the report before filing it.

Activity

  1. added
    bugSomething isn't working
    denoIssues related to deno
    on Oct 22, 2026
  2. cderv commented on Oct 22, 2026

    @cderv
    Member

    Thank you. We'll upgrade deno to latest for next v1.11 release.

    would a 1.10.x patch release with Deno ≥ 2.9.8 be feasible?

    Upgrading deno is more impact that we usually backport, so I'll need to look into this report specifically and see if upgrading Deno is the only option.

  3. cderv commented on Oct 22, 2026

    @cderv
    Member

    I looked into this, and upgrading Deno is the only real fix here. I can reproduce on Windows with the Deno 2.7.14 we bundle, and Deno 2.9.8 rejects both test endpoints.

    Setting DENO_TLS_CA_STORE can't help on Quarto side anyway, as our launchers always set it to system,mozilla

    export DENO_TLS_CA_STORE=system,mozilla

    std::env::set_var("DENO_TLS_CA_STORE","system,mozilla");

    The fix in Deno 2.9.8 is in the certificate path verification itself (denoland/deno#37046), so it applies whatever the store is, and no Deno older than 2.9.8 has it.

    Next steps

    For 1.11 we'll upgrade to Deno 2.9.8 or later. For a 1.10.x backport, this is a jump from Deno 2.7 to 2.9 so I want to see how it goes on main first before deciding. I'll update here.

    🤖 Analysis I ran with Claude Code to understand the problem and the risk

    What changed in Deno 2.9.8 (denoland/deno#37046)

    Probe from the report, run on Windows x64 with each CA store mode

    DENO_TLS_CA_STORE Deno 2.7.14 (bundled) Deno 2.9.8
    unset (default) both ACCEPTED both rejected
    system,mozilla (what Quarto sets) both ACCEPTED both rejected
    mozilla both ACCEPTED both rejected
    system G3 endpoint rejected, aaa endpoint ACCEPTED both rejected

    The 2.9.8 rejections are invalid peer certificate errors, and a normal site (github.com) still fetches fine. With system only, 2.7.14 still accepts the aaa endpoint because it chains through a cross-signed root that the Windows store trusts.

    Who is at risk

    Exploiting this requires a network position between the user and the server (hostile public Wi-Fi, compromised router or proxy, ...). Without it, nothing happens. With it, an attacker can impersonate any HTTPS host to Quarto, because the compromised keys can sign certificates for any hostname. Browsers already block these certificates, so non-browser clients like an older Deno are what remains exposed.

    Quarto commands that make HTTPS requests from Deno

    • quarto publish to Posit Connect, Posit Connect Cloud, Quarto Pub, Netlify and Confluence: API tokens and credentials could be captured, and published content altered.
    • quarto add, quarto use template, extension install: downloaded code could be replaced, and extensions run Lua filters during render.
    • quarto install (TinyTeX, Chrome Headless Shell): downloaded binaries could be replaced.
    • Smaller paths: remote resources fetched during render, giscus, reveal.js multiplex token.

    Not affected: offline rendering, git push for GitHub Pages (git has its own TLS), and Pandoc, R, Python and Julia, which use their own TLS stacks.

  4. cderv commented on Oct 23, 2026

    @cderv
    Member

    The fix for 1.11 is in #15186, which bumps the bundled Deno to 2.9.8. With the dev build, the probe from this issue now rejects both eMudhra endpoints with invalid peer certificate: CertDistrusted, and github.com still fetches fine. It will ship in 1.11 once the PR is merged.

    For 1.10.x the question is still open. The bump is a jump from Deno 2.7 to 2.9, and a backport would have to carry more than the version change: the Deno KV cache isolation from #15180 (otherwise caches written by 2.9 break earlier 1.10.x installs with RangeError: could not deserialize value), plus the compatibility fixes listed in #15186 (vendoring flags, TypeScript 6 type fixes, a bad-port exclusion, error cause printing).

    That is a heavy change for a stable branch, so I want to study it properly before deciding, ideally after the bump has had some exposure on main. I'll update here when we have a decision.

  5. self-assigned this
    on Oct 23, 2026
  6. added this to the v1.11 milestone on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdenoIssues related to deno

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions