8000 SECURITY: deno, claude-code: default to the system trust store (CVE-2026-111943) by bryan-minimal · Pull Request #956 · gominimal/pkgs · GitHub
[go: up one dir, main page]

Skip to content

SECURITY: deno, claude-code: default to the system trust store (CVE-2026-111943) - #956

Merged
bryan-minimal merged 2 commits into
mainfrom
security/deno-claude-system-ca
Oct 21, 2026
Merged

bryan-minimal merged 2 commits into
mainfrom
security/deno-claude-system-ca

Conversation

@bryan-minimal
Copy link
Copy Markdown
Member

What

CVE-2026-111943. The private keys of eight eMudhra intermediate CAs are recoverable from their public certificates (Mozilla bug 2083449). In Mozilla-derived stores those intermediates chain to emSign ECC Root CA - G3. NSS 3.131.1 drops it, and so does curl's cacert-2026-10-20.

deno and claude-code are prebuilt and carry their own compiled-in root sets, which the ca-certificates fix (#948) doesn't reach. Neither has a fixed upstream release, but both can be told to trust only the OS store. This PR makes that the default in their existing /usr/bin wrappers. The wrappers use the house : "${VAR:=default}" pattern (deno's DENO_INSTALL_ROOT, bun's BUN_INSTALL_BIN, pnpm's PNPM_CONFIG_GLOBAL_BIN_DIR), so a caller's own value still wins.

package compiled-in store upstream fix default set here
deno 2.9.7 webpki-roots 0.26.1 (includes ECC G3) via the default DENO_TLS_CA_STORE=mozilla; rustls-webpki 0.103.13 (no SPKI blocklist) denoland/deno#37046 (9766cc5e, merged 2026-10-20: rustls-webpki 0.103.16, webpki-roots 1.0.10). No release yet; 2.9.7 is the newest tag. DENO_TLS_CA_STORE=system
claude-code 2.1.292 Bun 1.4.3 runtime (Bun v1.4.3 in the binary). The DER of emSign ECC G3, C1 and C3 is each present once (checked by byte search against the pinned binary, sha a967e7b1…). Default CLAUDE_CODE_CERT_STORE=bundled,system. Needs a Bun release with oven-sh/bun#46159 (merged 10-20, unreleased; latest is v1.4.3). The CHANGELOG for 2.1.293–2.1.305 has no root-store change. CLAUDE_CODE_CERT_STORE=system

Why "system" drops the bundled roots

  • deno: cli/lib/args.rs at v2.9.7 uses the DENO_TLS_CA_STORE list in place of the default ["mozilla"]. system loads only native certs: SSL_CERT_FILE / SSL_CERT_DIR, else /etc/ssl/certs/ca-certificates.crt.
  • claude-code:
    • The network-config docs say: "Recognized values are bundled … and system …. The default is bundled,system", and describe system as "trust only the OS certificate store".
    • Claude Code builds its CA list itself. The binary logs CA certs: Loaded N bundled root certificates / system CA certificates per store.
    • Bun 1.4.3's usockets treats an explicit ca as a replacement for the default store (openssl.c: "An explicit CA replaces the default trust store (Node.js semantics)"). bun 1.3.14 merged it into the defaults instead.
    • NODE_EXTRA_CA_CERTS is still appended, so corporate proxy CAs keep working.

Depends on #948 to be effective. The system store is only clean once ca-certificates drops emSign ECC G3 and Sectigo AAA Certificate Services. Merging this first is harmless: the current system store and the bundled sets are equally exposed today. Once both land, the emSign path and the Sectigo AAA cross-sign path both fail.

ca-certificates becomes a runtime dep of both packages, as it already is for edgedelta, capy and maki. With system, an absent store would mean no roots: every TLS connection would fail, and Claude Code couldn't reach its API.

Tests

  • deno: new standalone test tls_ca_store_default. It runs deno eval through the wrapper and checks that the default is system and that a caller's DENO_TLS_CA_STORE=mozilla is kept.
  • claude-code has no tests block. Both wrappers were exercised locally by extracting the generated script and pointing exec at a stub: unset → system, and a caller value (bundled,system / mozilla) is kept. deno's DENO_INSTALL_ROOT default is unchanged, including with HOME unset.
  • nickel format leaves both build.ncl files unchanged, and sh -n / bash -n pass on both scripts.
  • Blast radius: MINIMAL_SCIENCE_MODE=1 mip dump --packages --arch amd64 against main changes 4 hashes: deno, claude-code, claude, claude-code-minimal-plugin.

Unverified

  • Neither binary was run (linux ELF, no local containers per policy). Specifically:
    • That claude-code 2.1.292 with CLAUDE_CODE_CERT_STORE=system actually leaves its bundled roots out. That claim rests on the docs plus Bun 1.4.3's ca replacement semantics. Its JS is bytecode, so the code path couldn't be read.
    • That deno's system resolves /etc/ssl/certs/ca-certificates.crt in a session.
  • A session check would settle both:
    • claude --debug should log CA certs: stores=system and no bundled count.
    • A deno eval fetch to a public host should succeed, and one with SSL_CERT_FILE=/dev/null should fail.
  • pkgs CI skips standalone tests.

Follow-ups

  • deno: bump with the runner (update --package=deno) as soon as a release containing #37046 is cut. It adds the SPKI blocklist, which removing roots can't provide. Keep system as the default after that, or revert to mozilla; either is defensible.
  • claude-code: bump once a release ships on a Bun containing #46159. Separately, GCS stable is already 2.1.304, so we're behind regardless.

🤖 Generated with Claude Code

bryan-minimal and others added 2 commits October 20, 2026 15:58
deno 2.9.7 defaults to DENO_TLS_CA_STORE=mozilla: webpki-roots 0.26.1
compiled into the binary, which still trusts emSign ECC Root CA - G3 (anchor of
the compromised eMudhra intermediates), with rustls-webpki 0.103.13 (no SPKI
blocklist). The fix (denoland/deno#37046) is on main but in no release.

The /usr/bin/deno wrapper now defaults DENO_TLS_CA_STORE=system, which reads
only the OS store (fixed by the ca-certificates PR), and a caller's own value
still wins. ca-certificates becomes a runtime dep so "system" is never empty.
A standalone test checks the default and the override.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1943)

Claude Code 2.1.292 runs on Bun 1.4.3, whose compiled-in roots still carry
emSign ECC Root CA - G3 (and C1, C3); its default CLAUDE_CODE_CERT_STORE is
"bundled,system". No Bun release has oven-sh/bun#46159 yet, so no Claude Code
release has fixed roots.

The /usr/bin/claude wrapper now defaults CLAUDE_CODE_CERT_STORE=system
("trust only the OS certificate store" per the network-config docs), and a
caller's own value still wins. ca-certificates becomes a runtime dep so the
store is never empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bryan-minimal
bryan-minimal requested a review from a team as a code owner October 20, 2026 22:59
@coderabbitai
coderabbitai Bot commented Oct 20, 2026
Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 4 billable files and costs up to $1.00.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 14 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available. Your 35 included PR review attempts over the past 7 days set your current allowance at 4 reviews per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: gominimal/pkgs/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: c205261e-576b-44c5-b883-f43f9399b211
📥 Commits

Reviewing files that changed from the base of the PR and between 24009b6 and d613a71.

📒 Files selected for processing: 4
  • packages/claude-code/build.ncl
  • packages/claude-code/build.sh
  • packages/deno/build.ncl
  • packages/deno/build.sh
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@bryan-minimal
bryan-minimal added this pull request to the merge queue Oct 21, 2026
@bryan-minimal
bryan-minimal removed this pull request from the merge queue due to a manual request Oct 21, 2026
@bryan-minimal
bryan-minimal added this pull request to the merge queue Oct 21, 2026
Merged via the queue into main with commit e0b7c9c Oct 21, 2026
10 checks passed
@bryan-minimal
bryan-minimal deleted the security/deno-claude-system-ca branch October 21, 2026 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0