Skip to content

fix(cli): require patched Node 22.23.4 and bump undici for security fixes - #516

Merged
so0k merged 3 commits into
open-constructs:mainfrom
vianho:chore/node-22.23.4
Oct 24, 2026
Merged

so0k merged 3 commits into
open-constructs:mainfrom
vianho:chore/node-22.23.4

Conversation

@vianho

@vianho vianho commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Related issue

Fixes #515

Description

Bumps .nvmrc from 22.22.3 to 22.23.4, the patched 22.x release from the Node.js security release of 21 October 2026 (release notes: v22.23.4). It fixes several High-severity CVEs, including CVE-2026-111497 (Brotli) and CVE-2026-106069 / CVE-2026-106072 (tls).

.nvmrc is the single Node version source: every workflow's actions/setup-node step uses node-version-file: .nvmrc (including the release jobs), and mise reads it for local development. So this one-line change moves CI, release, and local dev onto the patched version. It follows the same pattern as #212.

This stays on the 22.x line, so the engines: >=22.19.0 floor in cdktn-cli and @cdktn/cli-core is unchanged. The Dockerfile superchain base image is pinned by digest and isn't touched here (see the open question in #515).

Tested locally on Node 22.23.4: pnpm install --frozen-lockfile, pnpm nx run-many -t build -p cdktn @cdktn/commons, and pnpm nx test cdktn all pass.

Checklist

  • I have updated the PR title to match CDKTN's style guide
  • (N/A) I have run the linter on my code locally
  • I have performed a self-review of my code
  • (N/A) I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if applicable
  • My changes generate no new warnings
  • (N/A) I have added tests that prove my fix is effective or that my feature works if applicable
  • New and existing unit tests pass locally with my changes

@so0k

so0k commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Thanks @vianho! To fix the October 2026 Node.js security release in one place, we've pushed the related security fixes onto this PR as separate commits so each can be reviewed on its own:

  1. 5d69c7a6b chore(deps): bump Node to 22.23.4 via .nvmrc (your original change: CI, release and local dev)
  2. 85d2cd197 fix(cli): require patched Node 22.23.4 as the engines minimum for cdktn-cli and @cdktn/cli-core. This is the follow-up you suggested in chore: bump .nvmrc to Node 22.23.4 (October 2026 security release) #515: we stay on the Node 22 floor but require the patched release, since the CLI's fetch path reaches Node's Brotli decoder (CVE-2026-111497 / "Node2Shell").
  3. 07868adcb fix(deps): bump undici 8.7.0 → 8.12.3. 8.7.0 is affected by ~20 undici advisories, several High (including TLS cert validation bypasses GHSA-2m5v-pch6-74hx / GHSA-w293-vg96-wgc3 and the content-encoding crash GHSA-xjj6-f33q-929c). This supersedes fix(deps): bump undici to 8.12.3 for security advisories #517.

I retitled the PR to fix(cli): ... so the change shows up in the release notes.

Release notes: users will see this change. Installing cdktn-cli on Node < 22.23.4 now prints an engines warning under npm/pnpm, or fails if engine-strict is set.

Still open: the Dockerfile superchain base, which also feeds the devcontainer and jsii-terraform:latest. The latest upstream superchain:1-bookworm-slim-node22 image was built on 15 Oct, before the Node release, so there is no patched image to pin yet. CI isn't affected because setup-node puts 22.23.4 first on PATH inside the container. We'll bump the digest once upstream publishes.

@so0k so0k changed the title chore(deps): bump Node to 22.23.4 via .nvmrc fix(cli): require patched Node 22.23.4 and bump undici for security fixes Oct 24, 2026
vianho and others added 3 commits October 24, 2026 18:50
Picks up the 21 Oct 2026 Node.js security release.

Fixes open-constructs#515
Node.js 22.23.4 (21 Oct 2026 security release) fixes CVE-2026-111497
(Brotli decoder OOB write, "Node2Shell"), which the CLI's undici fetch
reaches when decoding br responses from registries, plus tls/dns/http
CVEs and the eMudhra CA distrust. Keep the Node 22 floor but require
the patched release.
@cdktn/cli-core uses undici's fetch/ProxyAgent for every outbound
registry call (registry-api.ts, prebuilt-providers.ts,
package-manager.ts). The exact 8.7.0 pin is affected by ~20 undici
advisories fixed in 8.10.2 / 8.12.2, including:

- GHSA-2m5v-pch6-74hx (High): TLS cert validation bypass via dropped
  tls options in Agent
- GHSA-w293-vg96-wgc3 (High): TLS cert validation bypass via dropped
  connect options in BalancedPool
- GHSA-4w7w-5xrc-9h26 (High): cache poisoning via cross-origin redirects
- GHSA-xjj6-f33q-929c (High): process crash on excessive
  content-encodings, even when the fetch() rejection is caught
- GHSA-qrxm-fqhp-jwvm (High): DoS via TLS 1.2 renegotiation
- GHSA-3xpg-4rpp-hhhm (Medium): unbounded decompression of responses

8.8.0 -> 8.12.3 has no breaking changes for the APIs we use. Lockfile
churn is limited to the undici entries.

This does not fix the Node.js Brotli CVE (CVE-2026-111497): undici
decodes br through Node's own zlib, which the Node 22.23.4 floor covers.
@so0k
so0k force-pushed the chore/node-22.23.4 branch from 07868ad to 98253aa Compare October 24, 2026 11:50
@so0k
so0k marked this pull request as ready for review October 24, 2026 11:50
@so0k
so0k requested a review from a team as a code owner October 24, 2026 11:50
@sakul-learning

Copy link
Copy Markdown
Contributor

Reviewed current head 98253aa6: .nvmrc and both CLI package engine floors consistently require Node 22.23.4, and the undici 8.12.3 manifest/lockfile update is consistent. All configured checks pass (37 focused tests, build, and 690 full-suite tests).

Verdict: APPROVE.

@so0k
so0k enabled auto-merge (squash) October 24, 2026 14:20
@so0k
so0k disabled auto-merge October 24, 2026 14:57
@so0k
so0k merged commit 76436f5 into open-constructs:main Oct 24, 2026
265 checks passed
so0k added a commit that referenced this pull request Oct 25, 2026
)

### Related issue

Follow-up to #516: the `docker` workflow on `main` has been failing
since 2026-10-24 (runs 40087773788, 40104821892 and its re-run).

### Description

`docker.yml` builds the root `Dockerfile`, whose base image is
`public.ecr.aws/jsii/superchain:1-bookworm-slim-node22@sha256:…`. The
pull is anonymous, and public.ecr.aws rejects it from GitHub-hosted
runners with `toomanyrequests: Data limit exceeded` before any layer is
fetched. The anonymous data cap is applied per source IP, and the
runners share IPs. It failed 3 of 3 attempts on different runners, while
the same digest resolves fine from outside GitHub.

This PR makes the build pull with authentication:

- Adds `id-token: write` to the `build-docker-image` job.
- `aws-actions/configure-aws-credentials` (v6.3.0, SHA-pinned) assumes
`vars.AWS_ECR_PULL_ROLE_ARN` in `us-east-1`, the only region where ECR
Public auth is served.
- `docker/login-action` (already pinned in this workflow) logs in to
`public.ecr.aws` with those credentials.

The role was created in open-constructs/cdk-terrain-iac#12
(`github-actions-role` stack) and is already applied:

- Trust: `StringEquals` on `sub =
repo:open-constructs/cdk-terrain:ref:refs/heads/main` and `aud =
sts.amazonaws.com`. Only `main` can assume it, which matches the job's
existing `refs/heads/main` guard.
- Permissions: only `ecr-public:GetAuthorizationToken` and
`sts:GetServiceBearerToken`. Max session is 1h.

The `AWS_ECR_PULL_ROLE_ARN` repo variable is set. Because `docker.yml`
only runs on `main`, the login is first exercised by the post-merge run.

### Checklist

- [x] I have updated the PR title to match [CDKTN's style
guide](https://github.com/open-constructs/cdk-terrain/blob/main/CONTRIBUTING.md#pull-requests-1)
- [x] I have run the linter on my code locally (actionlint, zizmor (no
new findings), prettier)
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] (N/A) I have made corresponding changes to the
[documentation](https://github.com/open-constructs/cdk-terrain-docs/tree/main/content)
if applicable
- [x] My changes generate no new warnings
- [x] (N/A) I have added tests that prove my fix is effective or that my
feature works if applicable
- [x] (N/A) New and existing unit tests pass locally with my changes
so0k pushed a commit that referenced this pull request Oct 27, 2026
🤖 Release PR — merge to cut a new release. Kept open and rebased
as commits land on `main`.
---


<details><summary>0.25.0</summary>

##
[0.25.0](v0.24.0...v0.25.0)
(2026-10-27)


### ⚠ BREAKING CHANGES

* **lib:** `IAssetPackaging` gains `acceptsDirectorySource` as a
required member. Custom implementations of the interface must add it.
* **lib:** ValidateBinaryVersion and ValidateTerraformVersion are
removed (they were only reachable through deep imports, not the cdktn
package root). Synth no longer executes the terraform/tofu binary for
feature validation; set validateInstalledBinary: true in cdktf.json to
verify the installed binary before commands that run it.
* **lib:** resource moves (moved blocks) are now validated at synth
against the project's declared targetVersions (default terraform
>=1.5.7, opentofu >=1.6.0) instead of the locally installed binary.
Projects that declare terraform targets below 1.5.0 now fail synth;
projects whose installed binary is older than their declared targets
should set validateInstalledBinary: true in cdktf.json.
* **lib:** import blocks (importFrom / ImportableResource) are now
validated at synth against the project's declared targetVersions
(default terraform >=1.5.7, opentofu >=1.6.0) instead of the locally
installed binary. Projects that declare terraform targets below 1.5.0
now fail synth; projects whose installed binary is older than their
declared targets should set validateInstalledBinary: true in cdktf.json.
* **lib:** terraform_data resources are now validated at synth against
the project's declared targetVersions (default terraform >=1.5.7,
opentofu >=1.6.0) instead of the locally installed binary. Projects that
declare terraform targets below 1.4.0 now fail synth; projects whose
installed binary is older than their declared targets should set
* **lib:** cloud backends (the cloud block) are now validated at synth
against the project's declared targetVersions (default terraform
>=1.5.7, opentofu >=1.6.0) instead of the locally installed binary.
Projects that declare terraform targets below 1.1.0 now fail synth;
projects whose installed binary is older than their declared targets
should set validateInstalledBinary: true in cdktf.json.
* **lib:** IAssetPackaging gains a required member
omitsDirectoryEntries; external implementations must add it. Custom
TerraformAsset assetHash values are now validated against
`/^[A-Za-z0-9_.-]+$/` and throw if they contain other characters (e.g.
"feature/my-branch").
* **lib:** add asset pipeline foundation types and hash utilities
([#371](#371))

### Features

* **cli:** add a typescript-pnpm init template and deprecate Yarn
([#422](#422))
([81da164](81da164))
* **cli:** move the TypeScript template to tsx and TypeScript 6
([#396](#396))
([b50349d](b50349d))
* **cli:** point AI coding agents at the CDKTN docs MCP server
([#518](#518))
([f257cd9](f257cd9))
* **cli:** rename `--cdktf-version` to `--cdktn-version` in `init`
([#228](#228))
([dd3818e](dd3818e))
* **cli:** replace HashiCorp checkpoint telemetry with Sentry usage
metrics and consent
([#411](#411))
([e17046a](e17046a))
* **cli:** report aggregated stack, provider and command usage metrics
([#413](#413))
([ed9b1e5](ed9b1e5))
* **cli:** report the installed binary, target versions, platform and
package manager in usage metrics
([#412](#412))
([bfe26a8](bfe26a8))
* **cli:** resolve providers from the registry the project targets
([#445](#445))
([78898ae](78898ae))
* **deps:** adopt jsii 6.0 and TypeScript 6
([#395](#395))
([26fa8fa](26fa8fa))
* **gha:** Revert "run the affected unit tests against OpenTofu
([#439](#439))"
([#446](#446))
([ae015ef](ae015ef))
* **gha:** run the affected unit tests against OpenTofu
([#439](#439))
([823682d](823682d))
* **gha:** run the affected unit tests against OpenTofu
([#447](#447))
([c0c4c1c](c0c4c1c))
* **lib:** add asset bundling extension interface
([#442](#442))
([7839625](7839625))
* **lib:** add asset pipeline foundation types and hash utilities
([#371](#371))
([a008d12](a008d12))
* **lib:** add asset staging core with no bundling
([#433](#433))
([44d8bd1](44d8bd1))
* **lib:** add support for single-file bundler outputs
([#464](#464))
([3592db0](3592db0))
* **lib:** pass ignore strategy through terraform asset
([#472](#472))
([705e5b9](705e5b9))
* **tests:** add per-test runtime pinning to the integration matrix
([#405](#405))
([17c2278](17c2278))


### Bug Fixes

* **cli:** catch failures of the background environment collection
([#531](#531))
([c5feed8](c5feed8))
* **cli:** correct the constructs range comment in the TypeScript
template hook
([#408](#408))
([9fc0e43](9fc0e43))
* **cli:** don't crash after a successful deploy when an output is
missing
([#375](#375))
([0bbd64a](0bbd64a))
* **cli:** fail cleanly when the --outputs-file write fails
([#376](#376))
([8f9d03a](8f9d03a))
* **cli:** make `cdktn get` remove stale files for resources removed
from a provider
([#421](#421))
([d6e28dc](d6e28dc))
* **cli:** match prebuilt providers regardless of the project's registry
([#493](#493))
([ea82124](ea82124))
* **cli:** probe with `version` instead of `-v`
([#471](#471))
([b87ee22](b87ee22))
* **cli:** require patched Node 22.23.4 and bump undici for security
fixes
([#516](#516))
([76436f5](76436f5))
* **cli:** resolve bundled handlers next to the entrypoint
([#414](#414))
([49600c1](49600c1))
* **cli:** resolve upgraded providers from the CLI's own registry
([#489](#489))
([10672ee](10672ee))
* **cli:** stop the top-level error handler racing yargs
([#410](#410))
([5d0c2ef](5d0c2ef))
* **deps:** move jsii-rosetta to 6.0.16 for stream-json 3
([#463](#463))
([f1ec16f](f1ec16f))
* **gha:** authenticate to public.ecr.aws in the docker image build
([#519](#519))
([c65bf2f](c65bf2f))
* **gha:** don't fail the pnpm upgrade jobs on ignored dep builds
([#399](#399))
([5b66342](5b66342))
* **gha:** move the jsii package cache out of the container HOME
([#514](#514))
([df5b490](df5b490))
* **gha:** pass -R to gh pr edit in release_github relabel step
([#372](#372))
([358edc7](358edc7))
* **gha:** push only the prerelease tag from prepare-next
([#476](#476))
([848f2a6](848f2a6))
* **lib:** avoid terraform init plugin-cache race in test matchers
([#467](#467))
([26847f9](26847f9))
* **lib:** retry the staging install without --prefer-offline outside CI
([#407](#407))
([7bb26e7](7bb26e7))
* **provider-generator:** pass the default provider configuration a
module requires on get
([#466](#466))
([a5225ab](a5225ab))
* **provider-generator:** pick the docs registry from targetVersions
([#443](#443))
([00f2884](00f2884))
* **provider-generator:** pick the module docs registry from
targetVersions
([#484](#484))
([8200330](8200330))
* **provider-generator:** regenerate bindings when the target registry
changes
([#490](#490))
([813e022](813e022))
* **provider-generator:** satisfy module provider configuration aliases
on get
([#383](#383))
([54a8217](54a8217))
* **provider-generator:** stop a provider_functions resource clobbering
the functions submodule
([#403](#403))
([cf19de9](cf19de9))
* **tests:** await the pip install in the python provider command tests
([#478](#478))
([1c83a36](1c83a36))
* **tests:** bound and retry the dist publish to the local registry
([#425](#425))
([cc9f9e2](cc9f9e2))
* **tests:** build the edge provider bindings in their own cached Nx
target
([#482](#482))
([f480cc9](f480cc9))
* **tests:** drop unused ts-jest transform from shared jest preset
([#382](#382))
([03f6e16](03f6e16))
* **tests:** mark the terraform-cloud target Terraform-only in the
matrix
([#430](#430))
([b0deefa](b0deefa))
* **tests:** run example builds with the Nx cache skipped
([#477](#477))
([3e25e13](3e25e13))
* **tools:** declare the cdktn-cli bundle as a cached Nx output with its
real inputs
([#485](#485))
([10dd118](10dd118))
* **tools:** make the workspace build, package, lint and test on Windows
([#364](#364))
([8dcddbe](8dcddbe))


### Code Refactoring

* **lib:** Remove the ValidateBinaryVersion synth-time binary probe
([#457](#457))
([e60142e](e60142e))
* **lib:** Use declared targetVersions for synth-time validation of
import blocks
([#454](#454))
([c0097f4](c0097f4))
* **lib:** Use declared targetVersions for synth-time validation of
resource moves
([#453](#453))
([43edc1e](43edc1e))
* **lib:** Use declared targetVersions for synth-time validation of
terraform_data
([#455](#455))
([a1c125b](a1c125b))
* **lib:** Use declared targetVersions for synth-time validation of the
cloud backend
([#456](#456))
([4a83507](4a83507))


### Miscellaneous Chores

* add OpenTofu and current Terraform to the jsii-terraform image
([#394](#394))
([2f29d5a](2f29d5a))
* declare complete Nx build outputs so cache hits restore them
([#474](#474))
([794cf77](794cf77))
* **deps:** move the remaining packages to TypeScript 6
([#406](#406))
([c55d360](c55d360))
* **deps:** move the root TypeScript to 6
([#417](#417))
([3cae1e2](3cae1e2))
* **deps:** Update xstate to v5.32.4
([#333](#333))
([5ebf74f](5ebf74f))
* **deps:** upgrade @sentry/node to 10.x
([#409](#409))
([2714fff](2714fff))
* **deps:** use caret ranges for unbundled runtime dependencies
([#503](#503))
([e722357](e722357))
* **docs:** add the test-audit skill for authoring and auditing tests
([#475](#475))
([909c612](909c612))
* **examples:** move the TypeScript examples to tsx and TypeScript 6
([#419](#419))
([857e182](857e182))
* Flexible python version
([#420](#420))
([955f62a](955f62a))
* **gha:** adopt the new jsii-terraform image and test Terraform 1.5.7 +
1.16.1
([#398](#398))
([3ad760b](3ad760b))
* **gha:** gate dependency upgrades on release age
([#418](#418))
([b611a87](b611a87))
* **gha:** retire Docker Hub publishing of jsii-terraform
([#388](#388))
([e53cddf](e53cddf))
* **gha:** select the CLI by binary name instead of concatenating a
version
([#438](#438))
([914da56](914da56))
* **gha:** skip the remote Nx cache in the release workflow
([#487](#487))
([bce91da](bce91da))
* **lib:** stop publishing build state in the cdktn package
([#397](#397))
([51e4a95](51e4a95))
* npm-check-updates && pnpm update
([#326](#326))
([7095f6b](7095f6b))
* **readme:** point to the cdktn-io/action GitHub Action
([#504](#504))
([e387852](e387852)),
closes [#58](#58)
* **tests:** add timeout handling to spawned commands
([#432](#432))
([ddb4a8a](ddb4a8a))
* **tests:** run the function-binding scripts with tsx
([#431](#431))
([fec67bf](fec67bf))


### Tests

* **lib:** ensure TerraformAsset stage within stack own directory
([#434](#434))
([9a80366](9a80366))
* **lib:** move matcher Docker fixture to a provider version OpenTofu
accepts
([#429](#429))
([7b0da12](7b0da12))
* **tests:** move the python providers fixture to Docker provider 3.9.0
([#440](#440))
([a678473](a678473))
* **tests:** move the remaining kreuzwerker/docker pins off unsigned
versions
([#459](#459))
([d855cc1](d855cc1))
* **tests:** move the testing-matchers fixtures to Docker provider 3.x
([#436](#436))
([8e2c60e](8e2c60e))
* **tests:** re-enable the Python edge integration test
([#404](#404))
([0a80626](0a80626))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: open-constructs-cdktn[bot] <291052431+open-constructs-cdktn[bot]@users.noreply.github.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.

chore: bump .nvmrc to Node 22.23.4 (October 2026 security release)

3 participants