Skip to content

fix(build): build and ship on Node 24.22.1 and 22.23.4 - #607

Merged
tnunamak merged 2 commits into
mainfrom
fix/node-24-22-1-emudhra
Oct 28, 2026
Merged

tnunamak merged 2 commits into
mainfrom
fix/node-24-22-1-emudhra

Conversation

@tnunamak

@tnunamak tnunamak commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

The Core, reference and n.eko images build on Node 24.19.0, and the desktop release ships a Node 24.21.0 sidecar. Both bundle a CA store that still trusts the compromised eMudhra intermediates, and connectors make their API calls through that Node. This PR moves every Node pin to the fixed releases (24.22.1 and 22.23.4).

Client fetch() dv-g3b fetch() ov-g3c fetch() www.debian.org
node:24.19.0-bookworm-slim (current image base) 200 200 200
node:24.22.1-bookworm-slim@sha256:55fb5f5a… (new base) CERT_REVOKED CERT_REVOKED 200

What changes: the image base in Dockerfile, deploy/docker/Dockerfile, deploy/railway/reference.Dockerfile and the n.eko Patchright stage, plus the two canary manifests that pin the same base; every setup-node pin and RELEASE_NODE_VERSION in scripts/stage-pdpp-node.mjs, so the desktop sidecar is 24.22.1; the one Node 22 workflow to 22.23.4; and @yao-pkg/pkg 6.24.0 in playwright-runner and personal-server, whose pkg-fetch 3.6.7 embeds Node 22.23.4 (6.22.0 embedded 22.23.2). Comments that record past measurements on older Node versions are left as they are.

Checked locally: scripts/release-workflow.test.ts (37), scripts/stage-pdpp-node.test.mjs (13) and canary-harness-manifest.test.ts (47) pass. Not checked locally: the image builds and the desktop release build; CI builds the images.

The Chrome-side fix for the same incident is #606.

Assisted-by: AI

The Core, reference and n.eko images run Node 24.19.0, and the desktop
release ships a Node 24.21.0 sidecar. Both Node versions bundle a CA
store that still trusts the compromised eMudhra intermediates. In
node:24.19.0-bookworm-slim, fetch() to the reporter's dv-g3b and ov-g3c
test hosts returns 200. In node:24.22.1-bookworm-slim, both fail with
CERT_REVOKED, and www.debian.org still loads. Connectors make their API
calls through Node, so the old Node in these images and in the desktop
app accepts a forged certificate from those intermediates.

This moves every Node pin to the fixed releases: the image base to
24.22.1 (pinned by digest), the CI and release setup-node pins and the
sidecar's RELEASE_NODE_VERSION to 24.22.1, the one Node 22 workflow to
22.23.4, and @yao-pkg/pkg to 6.24.0, whose pkg-fetch 3.6.7 embeds Node
22.23.4 in the playwright-runner binary (6.22.0 embedded 22.23.2).

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
tnunamak added a commit that referenced this pull request Oct 27, 2026
The check script started its CDP client container on node:24.19.0,
the Node release whose bundled CA store still trusts the compromised
eMudhra intermediates. Use the same 24.22.1 image as #607.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
The release builds personal-server with @yao-pkg/pkg 6.22.0, whose
pkg-fetch 3.6.5 embeds Node 22.23.2, so the shipped server still
carried the old CA store. pkg 6.24.0 (pkg-fetch 3.6.7) embeds 22.23.4,
the same bump as playwright-runner.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
tnunamak added a commit that referenced this pull request Oct 28, 2026
* fix(docker): distrust compromised eMudhra CAs in image browsers

On 20 October 2026 the private keys of eight eMudhra intermediate CAs were
shown to be recoverable from their certificates. Anyone can now issue a
certificate for any host that chains to them. The browsers in the Core,
reference-browser and n.eko images accept such certificates. Chrome blocks
these keys through its CRLSet, a list it downloads in the background. These
browsers run with --disable-background-networking and start a fresh process
for each run, so a run cannot count on having that list. Chrome for Testing,
the Patchright build these images run, also does not enforce Certificate
Transparency, so a certificate that was never publicly logged is accepted
too.

docker/chrome-policy/distrusted-cas.json is a Chrome machine policy that
sets CADistrustedCertificates to one certificate for each of the eight
keys. These are the six TLS keys that Chrome's CRLSet blocks and the two
code-signing keys that Go's crypto/x509 also distrusts. Chrome distrusts by
public key, so each entry also covers the key's AAA Certificate Services
cross-sign.

Chromium ignores a policy file outside the directory that its branding
reads. Chrome for Testing reads /etc/opt/chrome_for_testing, Google Chrome
reads /etc/opt/chrome and Chromium reads /etc/chromium. The existing n.eko
policies.json is only in the last two. The root and deploy Dockerfiles
install the new file for Chrome for Testing and Chromium. The n.eko
Dockerfile installs it for all three browsers that start-chromium.sh can
launch. policies.json is unchanged.

scripts/chrome-distrust-policy.test.ts checks that each entry is a CA
certificate with one of the eight keys, that each key is listed once, and
that each Dockerfile installs the file in the expected directories.
deploy/docker/check-chrome-distrust-policy.sh starts each browser in a
built image without network access and reads chrome://policy over the
DevTools Protocol. The policy value must equal the repository file, with
status OK. The docker-images workflow runs this check on the core,
reference-browser and n.eko images. n.eko's policies.json blocks
chrome://policy in Google Chrome and Chromium, so the script can read the
value only in Chrome for Testing there. For the other two browsers it
checks that the file is in place.

The researcher who disclosed the keys lists 14 test hosts whose
certificates chain through them. A test against all 14 used a new browser
process and an empty profile for each request, with CRLSet updates off. With the policy, every host was rejected in Chrome for
Testing 156.0.8078.4 (Core and n.eko), Google Chrome 156.0.8078.47 and
Chromium 143 (n.eko). Without it, Chrome for Testing and Chromium loaded
each host that chains through emSign, and Google Chrome loaded all but the
one whose certificate was never logged. Core's headed Patchright launch and n.eko's own
start-chromium.sh launch gave the same results.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>

* fix(docker): keep headless launches on policy-reading Chromium

With no channel, Patchright runs a headless launch in Chrome Headless
Shell, a separate build that does not read managed policy. In the Core
and reference-browser images, PDPP_BROWSER_HEADLESS=1 therefore ran
connectors in a browser that ignored the CA distrust policy: it loaded
the reporter's dv-g3b, ov-g3c and dv-g3b-noct hosts with HTTP 200.

The Patchright images now install Chromium with --no-shell, fail the
build if the headless shell appears, and set
PDPP_BROWSER_CHANNEL=chromium. Connector builds that already read that
variable therefore launch the full Chromium in both modes. The launcher
in packages/polyfill-connectors also defaults to the "chromium" channel
when the variable is unset. The Core demo smoke names the channel because
the image no longer has the headless shell.

check-chrome-distrust-policy.sh now fails an image that ships the
headless shell. It also requires every browser to show the policy value.
Before, a browser whose policies.json blocks chrome://policy counted as
passing even when its CA policy file was missing. Now the script removes
that one URLBlocklist entry, only inside its throwaway container, and
reads the values. Debian Chromium 143 shows the source, scope, level and
status without labels, so the page check reads them by position. A
watchdog now bounds every DevTools step.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>

* fix(docker): run the policy check client on Node 24.22.1

The check script started its CDP client container on node:24.19.0,
the Node release whose bundled CA store still trusts the compromised
eMudhra intermediates. Use the same 24.22.1 image as #607.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>

---------

Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
@tnunamak
tnunamak merged commit 99eacfd into main Oct 28, 2026
49 checks passed
@tnunamak
tnunamak deleted the fix/node-24-22-1-emudhra branch October 28, 2026 00:16
tnunamak added a commit that referenced this pull request Oct 28, 2026
Resolve managed-connector-oci-e2e.yml: keep this branch's Node 24 choice for the install-path journey job, at main's new 24.22.1 pin (#607).

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
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.

1 participant