Skip to content

fix: apply the certificate SPKI blocklist to Node and add entries - #55126

Merged
MarshallOfSound merged 1 commit into
mainfrom
cert-blocklist-update
Oct 20, 2026
Merged

MarshallOfSound merged 1 commit into
mainfrom
cert-blocklist-update

Conversation

@MarshallOfSound

Copy link
Copy Markdown
Member

Description of Change

  • Node: apply the SPKI blocklist to every SecureContext so a chain containing a listed key reports CERT_REVOKED, matching what the Chromium stack already does.
  • Chromium: add entries to the compiled-in SPKI blocklist that Chrome ships via CRLSet, which Electron does not consume.
  • Spec covering the Node path via testing-binding hooks.

Checklist

Release Notes

Notes: none

Chromium carries a compiled-in list of SubjectPublicKeyInfo hashes that
must never appear in a verified chain. Electron's Node had no equivalent,
so the same chain could fail in a renderer and succeed in tls/https/fetch
from the main or a utility process.

- Node: wrap X509_verify_cert on every SecureContext and report
  CERT_REVOKED when a chain contains a blocked SPKI.
- Chromium: add entries that Chrome distributes via CRLSet, which Electron
  does not consume, to the compiled-in list; Node's list mirrors them.
- Testing binding hooks let the new spec extend Node's list at runtime and
  exercise the hook against the fixture chain.
@MarshallOfSound
MarshallOfSound requested a review from a team as a code owner October 20, 2026 00:15
@MarshallOfSound MarshallOfSound added semver/patch backwards-compatible bug fixes target/42-x-y PR should also be added to the "42-x-y" branch. target/43-x-y PR should also be added to the "43-x-y" branch. target/44-x-y PR should also be added to the "44-x-y" branch. target/45-x-y PR should also be added to the "45-x-y" branch. labels Oct 20, 2026
@MarshallOfSound MarshallOfSound self-assigned this Oct 20, 2026
@trop

trop Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

@MarshallOfSound has manually backported this PR to "44-x-y", please check out #55127

@trop trop Bot added in-flight/44-x-y and removed target/44-x-y PR should also be added to the "44-x-y" branch. labels Oct 20, 2026
@trop

trop Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

@MarshallOfSound has manually backported this PR to "42-x-y", please check out #55128

@trop

trop Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

@MarshallOfSound has manually backported this PR to "45-x-y", please check out #55129

@trop trop Bot added in-flight/42-x-y and removed target/42-x-y PR should also be added to the "42-x-y" branch. labels Oct 20, 2026
@trop trop Bot removed the target/45-x-y PR should also be added to the "45-x-y" branch. label Oct 20, 2026
@trop

trop Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

@MarshallOfSound has manually backported this PR to "43-x-y", please check out #55130

@trop trop Bot added in-flight/45-x-y in-flight/43-x-y and removed target/43-x-y PR should also be added to the "43-x-y" branch. labels Oct 20, 2026
@trop trop Bot added merged/43-x-y PR was merged to the "43-x-y" branch. merged/45-x-y PR was merged to the "45-x-y" branch. and removed in-flight/43-x-y in-flight/45-x-y labels Oct 20, 2026
UlisesGascon added a commit to UlisesGascon/node that referenced this pull request Oct 20, 2026
Node.js embeds the Mozilla root store but has no equivalent of the
browsers' CRLSet/OneCRL and no default online revocation checking, so a
certificate chain through a compromised intermediate still verifies as
long as it reaches a trusted root. Removing the affected roots would
over-block, since other legitimate intermediates chain to them.

Add a small compiled-in blocklist of SubjectPublicKeyInfo SHA-256 hashes
and check every verified chain against it from a single
SSL_CTX_set_cert_verify_callback hook. A hit is reported as
X509_V_ERR_CERT_REVOKED through the normal verification path, so it
honours rejectUnauthorized and surfaces as authorizationError on both
client and server sockets. The hook is installed for every SSL_CTX
Node.js creates: SecureContext, QUIC and DTLS. The OpenSSL 4.1 CN name
constraint handling previously registered from crypto_tls.cc moves into
the same hook, since OpenSSL allows only one.

The initial entries are the eight eMudhra/emSign intermediates whose
private keys were reported compromised in October 2026. The same list is
shipped by Chromium, Go (CVE-2026-111943) and Electron.

Sessions resumed from before this change are not re-verified, as is
standard for TLS resumption; the exposure ends with the session timeout.

Test-only hooks on the crypto binding, reachable with --expose-internals,
allow the test to block a fixture key and exercise the full handshake.

Refs: electron/electron#55126
Refs: golang/go#82345
Assisted-by: Claude, Codex
Signed-off-by: Ulises Gascon <ulisesgascongonzalez@gmail.com>
UlisesGascon added a commit to UlisesGascon/node that referenced this pull request Oct 20, 2026
Node.js embeds the Mozilla root store but has no equivalent of the
browsers' CRLSet/OneCRL and no default online revocation checking, so a
certificate chain through a compromised intermediate still verifies as
long as it reaches a trusted root. Removing the affected roots would
over-block, since other legitimate intermediates chain to them.

Add a small compiled-in blocklist of SubjectPublicKeyInfo SHA-256 hashes
and check every verified chain against it from a single
SSL_CTX_set_cert_verify_callback hook. A hit is reported as
X509_V_ERR_CERT_REVOKED through the normal verification path, so it
honours rejectUnauthorized and surfaces as authorizationError on both
client and server sockets. The hook is installed for every SSL_CTX
Node.js creates: SecureContext, QUIC and DTLS. The OpenSSL 4.1 CN name
constraint handling previously registered from crypto_tls.cc moves into
the same hook, since OpenSSL allows only one.

The initial entries are the eight eMudhra/emSign intermediates whose
private keys were reported compromised in October 2026. The same list is
shipped by Go (CVE-2026-111943) and Electron.

Sessions resumed from before this change are not re-verified, as is
standard for TLS resumption; the exposure ends with the session timeout.

Test-only hooks on the crypto binding, reachable with
--expose-internals, allow the test to block a fixture key and exercise
the full handshake.

Refs: electron/electron#55126
Refs: golang/go#82345
Assisted-by: Claude, Codex
Signed-off-by: Ulises Gascon <ulisesgascongonzalez@gmail.com>
UlisesGascon added a commit to UlisesGascon/node that referenced this pull request Oct 20, 2026
Node.js embeds the Mozilla root store but has no equivalent of the
browsers' CRLSet/OneCRL and no default online revocation checking, so a
certificate chain through a compromised intermediate still verifies as
long as it reaches a trusted root. Removing the affected roots would
over-block, since other legitimate intermediates chain to them.

Add a small compiled-in blocklist of SubjectPublicKeyInfo SHA-256 hashes
and check every verified chain against it from a single
SSL_CTX_set_cert_verify_callback hook. A hit is reported as
X509_V_ERR_CERT_REVOKED through the normal verification path, so it
honours rejectUnauthorized and surfaces as authorizationError on both
client and server sockets. The hook is installed for every SSL_CTX
Node.js creates: SecureContext, QUIC and DTLS. The OpenSSL 4.1 CN name
constraint handling previously registered from crypto_tls.cc moves into
the same hook, since OpenSSL allows only one.

The initial entries are the eight eMudhra/emSign intermediates whose
private keys were reported compromised in October 2026. The same list is
shipped by Go (CVE-2026-111943) and Electron.

Sessions resumed from before this change are not re-verified, as is
standard for TLS resumption; the exposure ends with the session timeout.

Test-only hooks on the crypto binding, reachable with
--expose-internals, allow the test to block a fixture key and exercise
the full handshake.

Refs: electron/electron#55126
Refs: golang/go#82345
Assisted-by: Claude, Codex
Signed-off-by: Ulises Gascon <ulisesgascongonzalez@gmail.com>
@teutat3s teutat3s mentioned this pull request Oct 20, 2026
2 of 13 tasks
nodejs-github-bot pushed a commit to nodejs/node that referenced this pull request Oct 20, 2026
Node.js embeds the Mozilla root store but has no equivalent of the
browsers' CRLSet/OneCRL and no default online revocation checking, so a
certificate chain through a compromised intermediate still verifies as
long as it reaches a trusted root. Removing the affected roots would
over-block, since other legitimate intermediates chain to them.

Add a small compiled-in blocklist of SubjectPublicKeyInfo SHA-256 hashes
and check every verified chain against it from a single
SSL_CTX_set_cert_verify_callback hook. A hit is reported as
X509_V_ERR_CERT_REVOKED through the normal verification path, so it
honours rejectUnauthorized and surfaces as authorizationError on both
client and server sockets. The hook is installed for every SSL_CTX
Node.js creates: SecureContext, QUIC and DTLS. The OpenSSL 4.1 CN name
constraint handling previously registered from crypto_tls.cc moves into
the same hook, since OpenSSL allows only one.

The initial entries are the eight eMudhra/emSign intermediates whose
private keys were reported compromised in October 2026. The same list is
shipped by Go (CVE-2026-111943) and Electron.

Sessions resumed from before this change are not re-verified, as is
standard for TLS resumption; the exposure ends with the session timeout.

Test-only hooks on the crypto binding, reachable with
--expose-internals, allow the test to block a fixture key and exercise
the full handshake.

Refs: electron/electron#55126
Refs: golang/go#82345
Assisted-by: Claude, Codex
Signed-off-by: Ulises Gascon <ulisesgascongonzalez@gmail.com>
PR-URL: #66871
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Bryan English <bryan@bryanenglish.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
tec27 added a commit to ShieldBattery/ShieldBattery that referenced this pull request Oct 21, 2026
44.9.1 adds the eight weak eMudhra/emSign intermediate keys to an SPKI
blocklist that covers both Chromium's verifier and the main process's
Node TLS (electron/electron#55126); 44.9.3 adds a batch of Chromium/V8
security backports. Both are inside the release-age quarantine, so the
exact version is excluded from it.
fogtape pushed a commit to fogtape/nodejs-mobile that referenced this pull request Oct 21, 2026
Node.js embeds the Mozilla root store but has no equivalent of the
browsers' CRLSet/OneCRL and no default online revocation checking, so a
certificate chain through a compromised intermediate still verifies as
long as it reaches a trusted root. Removing the affected roots would
over-block, since other legitimate intermediates chain to them.

Add a small compiled-in blocklist of SubjectPublicKeyInfo SHA-256 hashes
and check every verified chain against it from a single
SSL_CTX_set_cert_verify_callback hook. A hit is reported as
X509_V_ERR_CERT_REVOKED through the normal verification path, so it
honours rejectUnauthorized and surfaces as authorizationError on both
client and server sockets. The hook is installed for every SSL_CTX
Node.js creates: SecureContext, QUIC and DTLS. The OpenSSL 4.1 CN name
constraint handling previously registered from crypto_tls.cc moves into
the same hook, since OpenSSL allows only one.

The initial entries are the eight eMudhra/emSign intermediates whose
private keys were reported compromised in October 2026. The same list is
shipped by Go (CVE-2026-111943) and Electron.

Sessions resumed from before this change are not re-verified, as is
standard for TLS resumption; the exposure ends with the session timeout.

Test-only hooks on the crypto binding, reachable with
--expose-internals, allow the test to block a fixture key and exercise
the full handshake.

Refs: electron/electron#55126
Refs: golang/go#82345
Assisted-by: Claude, Codex
Signed-off-by: Ulises Gascon <ulisesgascongonzalez@gmail.com>
PR-URL: nodejs/node#66871
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Bryan English <bryan@bryanenglish.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
DeJeune added a commit to CherryHQ/cherry-studio that referenced this pull request Oct 21, 2026
<!-- Template from
https://github.com/kubevirt/kubevirt/blob/main/.github/PULL_REQUEST_TEMPLATE.md?-->
<!--  Thanks for sending a pull request!  Here are some tips for you:
1. Consider creating this PR as draft:
https://github.com/CherryHQ/cherry-studio/blob/main/CONTRIBUTING.md
-->

### What this PR does

Before this PR: Electron 44.4.4 without the upstream eMudhra
certificate-key blocklist fix; Linux SQLite prebuilds pinned to that
version

After this PR: Electron 44.9.3 with the upstream certificate security
fix, synchronized lockfile, an exact-version release-age exception, and
verified x64/ARM64 SQLite prebuilds

<!-- (optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)`
format, will close the issue(s) when PR gets merged)*: -->

Fixes: N/A

### Why we need it and why it was done in this way

The following tradeoffs were made: stay on Electron 44; allow this exact
security release through the package-age gate

The following alternatives were considered: Electron 45 (unnecessary
major upgrade); Electron-only bump (breaks strict Linux native-version
validation)

Links to places where the discussion took place: [upstream
fix](electron/electron#55126), [Electron 44
backport](electron/electron#55127), [published
native
prebuilds](https://github.com/CherryHQ/cherry-studio-better-sqlite3/releases/tag/better-sqlite3-v12.11.1-electron-v44.9.3-r1)

### Agent Note / Spec

<!-- Link the note and Spec PR, or write `N/A — <reason>` for a
local/mechanical change. -->

Agent Note: N/A — mechanical upstream security update preserving the
existing native packaging contract

Spec PR: N/A — no new feature, architecture, or process

Acceptance criteria: Regression — patched Electron runtime and matching,
verified Linux prebuilds

### Verification

<!-- List only evidence actually run. Map Spec work to AC IDs; use
Regression/N/A for direct fixes or process changes. -->

- Regression — `pnpm test:scripts scripts/__tests__/linux-native.test.ts
scripts/__tests__/before-pack.test.ts`: 25/25 passed
- Regression — `pnpm typecheck:node` and `pnpm typecheck:web`: passed
- Regression — `pnpm rebuild:electron`: passed; actual Electron 44.9.3
runtime, ABI 149, and native `better-sqlite3` query verified on macOS
- Regression — production `ensureLinuxNativeArtifact()` download and
verification for x64/ARM64: passed; SHA-256, ELF architecture, Electron
metadata, and GLIBC limits verified
- Regression — `shasum -a 256 -c SHA256SUMS` and `gh attestation verify`
for both native addons, restricted to the release workflow, tag, and
source commit: passed
- Regression — [native prebuild Release
workflow](https://github.com/CherryHQ/cherry-studio-better-sqlite3/actions/runs/39600707391):
passed; signed commit and tag verified on GitHub
- N/A — `pnpm change:scope --base origin/main`, `pnpm check --plan`, and
`pnpm docs:affected --base origin/main`: inspected; app-upgrade and
Linux-packaging documentation remains accurate
- N/A — `pnpm exec oxfmt --check package.json pnpm-workspace.yaml
scripts/linux-native/release.json` and `git diff --check`: passed

### Breaking changes

<!-- optional -->

None

### Special notes for your reviewer

<!-- optional -->

Full application packaging and E2E not run; Linux prebuild release
already available, with addon hashes unchanged and versioned manifests
updated

### Checklist

This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.

- [x] Branch: This PR targets `main`
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [ ] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others

### Release note

<!--  Write your release note:
1. Enter your extended release note in the below block. If the PR
requires additional action from users switching to the new release,
include the string "action required".
2. If no release note is required, just write "NONE".
3. Only include user-facing changes (new features, bug fixes visible to
users, UI changes, behavior changes). For CI, maintenance, internal
refactoring, build tooling, or other non-user-facing work, write "NONE".
-->

```release-note
Updated Electron to block compromised eMudhra certificate keys in HTTPS connections.
```

Signed-off-by: suyao <sy20010504@gmail.com>
gnguralnick pushed a commit to imbue-ai/default-workspace-template that referenced this pull request Oct 22, 2026
… policy

The pinned Fortress (Chromium 151) still ships emSign ECC Root CA - G3,
and Playwright's --disable-component-update keeps Chrome's CRLSet from
reaching it. The Fortress env.d unit now writes a Chromium managed policy,
/etc/chromium/policies/managed/distrust-compromised-emudhra-intermediates.json,
whose CADistrustedCertificates lists the eight intermediates from Mozilla
bug 2083449, as base64 DER. Chromium distrusts by public key, so the
Sectigo cross-signs of the same keys are covered too.

Verified from Chromium 151.0.7908.0 source and the pinned Fortress binary,
not at runtime: Fortress is not Chrome-branded and its binary carries the
/etc/chromium/policies path and the CADistrustedCertificates policy
(M132+, dynamic refresh). The certificates' SPKI hashes match the blocklist
electron/electron#55126 adds; the new test checks the shipped policy
parses and names exactly those keys.
shaanmajid added a commit to shaan-forks/clients that referenced this pull request Oct 22, 2026
Electron 43.8.1 adds the eMudhra intermediate SPKI blocklist entries and applies the blocklist to Node TLS (electron/electron#55126, backported in #55130). 43.8.3 is the latest 43.x patch and also carries upstream Chromium security backports (electron/electron#55147).
Xmader pushed a commit to Distributive-Network/node that referenced this pull request Oct 23, 2026
Node.js embeds the Mozilla root store but has no equivalent of the
browsers' CRLSet/OneCRL and no default online revocation checking, so a
certificate chain through a compromised intermediate still verifies as
long as it reaches a trusted root. Removing the affected roots would
over-block, since other legitimate intermediates chain to them.

Add a small compiled-in blocklist of SubjectPublicKeyInfo SHA-256 hashes
and check every verified chain against it from a single
SSL_CTX_set_cert_verify_callback hook. A hit is reported as
X509_V_ERR_CERT_REVOKED through the normal verification path, so it
honours rejectUnauthorized and surfaces as authorizationError on both
client and server sockets. The hook is installed for every SSL_CTX
Node.js creates: SecureContext, QUIC and DTLS. The OpenSSL 4.1 CN name
constraint handling previously registered from crypto_tls.cc moves into
the same hook, since OpenSSL allows only one.

The initial entries are the eight eMudhra/emSign intermediates whose
private keys were reported compromised in October 2026. The same list is
shipped by Go (CVE-2026-111943) and Electron.

Sessions resumed from before this change are not re-verified, as is
standard for TLS resumption; the exposure ends with the session timeout.

Test-only hooks on the crypto binding, reachable with
--expose-internals, allow the test to block a fixture key and exercise
the full handshake.

Refs: electron/electron#55126
Refs: golang/go#82345
Assisted-by: Claude, Codex
Signed-off-by: Ulises Gascon <ulisesgascongonzalez@gmail.com>
PR-URL: nodejs#66871
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Bryan English <bryan@bryanenglish.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

46-x-y merged/42-x-y PR was merged to the "42-x-y" branch. merged/43-x-y PR was merged to the "43-x-y" branch. merged/44-x-y PR was merged to the "44-x-y" branch. merged/45-x-y PR was merged to the "45-x-y" branch. semver/patch backwards-compatible bug fixes

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants