From 7052f642b0b6e12ea1ff5e45c33717001aa86938 Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Fri, 23 Oct 2026 11:46:08 -0700 Subject: [PATCH 1/3] Fix October 2026 Node.js security baseline Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/docs.yml | 13 ++- .github/workflows/performance.yml | 6 +- .github/workflows/pr-validation.yml | 22 ++++- CHANGELOG.md | 1 + CONTRIBUTING.md | 15 ++- README.md | 32 ++++++- docs/fabric-getting-started.md | 2 +- package-lock.json | 2 +- package.json | 2 +- samples/README.md | 2 +- samples/agent365-s2s/README.md | 2 +- samples/agent365-s2s/package-lock.json | 4 +- samples/agent365-s2s/package.json | 2 +- samples/aks-langchain/Dockerfile | 4 +- samples/aks-langchain/README.md | 8 +- samples/aks-langchain/package-lock.json | 2 +- samples/aks-langchain/package.json | 2 +- samples/fabric/README.md | 3 + samples/fabric/package.json | 3 + samples/package-lock.json | 4 +- samples/package.json | 2 +- scripts/check-node-version.cjs | 32 +++++++ test/integration/node-version.test.mjs | 117 ++++++++++++++++++++++++ 23 files changed, 258 insertions(+), 24 deletions(-) create mode 100644 scripts/check-node-version.cjs create mode 100644 test/integration/node-version.test.mjs diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 87bf07cc8..1612259c8 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,6 +28,14 @@ jobs: with: fetch-depth: 2 + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: "22.23.4" + + - name: Verify Node.js security baseline + run: node scripts/check-node-version.cjs + - name: Check if version changed id: version run: | @@ -54,7 +62,10 @@ jobs: - name: Set up Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: "22" + node-version: "22.23.4" + + - name: Verify Node.js security baseline + run: node scripts/check-node-version.cjs - name: Install dependencies run: npm ci diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 1e1ad8a1e..11304eec6 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -36,10 +36,14 @@ jobs: - name: Set up Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: "22" + node-version: "22.23.4" cache: npm cache-dependency-path: pr/package-lock.json + - name: Verify Node.js security baseline + working-directory: pr + run: node scripts/check-node-version.cjs + - name: Install and build candidate working-directory: pr run: | diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml index 7f48864c3..583780bd5 100644 --- a/.github/workflows/pr-validation.yml +++ b/.github/workflows/pr-validation.yml @@ -19,7 +19,10 @@ jobs: - name: Set up Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: "22" + node-version: "22.23.4" + + - name: Verify Node.js security baseline + run: node scripts/check-node-version.cjs - name: Install dependencies run: npm ci @@ -42,7 +45,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: ["22", "24"] + node-version: ["22.23.4", "24.22.1"] steps: - name: Check out repository @@ -53,6 +56,12 @@ jobs: with: node-version: ${{ matrix.node-version }} + - name: Verify Node.js security baseline + run: node scripts/check-node-version.cjs + + - name: Test Node.js security baseline guard + run: node --test test/integration/node-version.test.mjs + - name: Install dependencies run: npm ci @@ -79,9 +88,12 @@ jobs: - name: Set up Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: "22" + node-version: "22.23.4" cache: npm + - name: Verify Node.js security baseline + run: node scripts/check-node-version.cjs + - name: Install dependencies run: npm ci @@ -104,7 +116,9 @@ jobs: - name: Set up Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: "22" + node-version: "22.23.4" + - name: Verify Node.js security baseline + run: node scripts/check-node-version.cjs - name: Install dependencies run: npm ci - name: Build diff --git a/CHANGELOG.md b/CHANGELOG.md index bd58530b0..2c93656b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] ### Bugs Fixed +- Require the full [October 21, 2026 Node.js security baseline](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases): 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x. Pin CI and the AKS sample image, verify the selected runtime, and align sample requirements and lockfile metadata. Include encoding-only compression paths as precautionary hardening without changing compression behavior. Customers must patch and redeploy their Node.js runtimes; upgrading this package alone does not remediate runtime CVEs. - **Breaking change on Unix (Linux/macOS):** Agent365 offline buffering/replay now requires an explicitly configured, existing, absolute `durableDelivery.storageDirectory`. No automatic Unix temporary-directory fallback or root creation. Missing/invalid roots are logged and disable only disk buffering/replay; online export continues. Customers provision and maintain ownership, permissions (normally a private service-account-owned `0700` root), ACLs, and path-replacement protection; the SDK does not inspect or repair Unix access controls. Windows behavior, explicit-root cache identities, record compatibility, and retention limits are unchanged. Old temporary backlogs are not automatically migrated; see [storage provisioning and migration](A365_DOCUMENTATION.md#storage-provisioning-and-migration). ### Features Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b5776e90..7603bc38e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,17 +14,27 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope ## Development Setup -1. Install [Node.js](https://nodejs.org/) 22 or later. +1. Install patched [Node.js](https://nodejs.org/): 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x. See the [runtime requirements](README.md#nodejs-runtime-requirements). 2. Install dependencies. 3. Run formatting, linting, and tests before opening a pull request. ```bash +node scripts/check-node-version.cjs npm install npm run build npm run lint npm test ``` +CI pins Node.js 22.23.4 and 24.22.1 and checks `process.versions.node` before +running repository commands. The guard checks the actual executable, not a +version argument or environment override. Its dependency-free regression tests +can be run with `node --test test/integration/node-version.test.mjs`. +Keep runtime pins and package/lockfile engine metadata aligned when updating +the security baseline. GitHub Actions' embedded Node runtimes are managed by +the action/runner providers; `actions/setup-node` only selects the runtime for +subsequent repository commands. + ### Using package-lock.json The committed `package-lock.json` is generated through Microsoft's package proxy. @@ -66,7 +76,8 @@ the required proxy rather than using this workflow to bypass its restrictions. ## SDK performance benchmarks -After building, run the standalone harness on Node.js 22 or later. It measures +After building, run the standalone harness on a patched Node.js version from +the [runtime requirements](README.md#nodejs-runtime-requirements). It measures recording span creation (with and without an attribute), counter aggregation, and log emission through the built SDK. Non-exporting processors and a metric reader keep serialization, network transport, and exporter batching out of the diff --git a/README.md b/README.md index c48502402..213e1ccd5 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,41 @@ Microsoft OpenTelemetry distribution for Node.js — one import, one call, full npm install @microsoft/opentelemetry ``` +### Node.js runtime requirements + +Use the [October 21, 2026 Node.js security releases](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases) +or a later patched release on your supported Node.js line: + +| Node.js line | Minimum version | +| ------------ | --------------- | +| 22.x | 22.23.4 | +| 24.x | 24.22.1 | +| 26.x | 26.12.1 | + +The package engine range is `^22.23.4 || ^24.22.1 || >=26.12.1`. End-of-life +Node.js 23 and 25 are excluded; future stable majors remain eligible. CI retains +Node.js 22 and 24 coverage. + +This baseline addresses the full advisory, not only the Brotli decoder issue: +DNS, TLS hostname validation, HTTP keep-alive handling, snapshot entropy caches, +permission checks, the Node.js 26 ZIP issue, and the applicable bundled c-ares, +CA certificate, OpenSSL, SQLite, and Undici updates. The SDK's opt-in browser +injection uses Node's Brotli decoder and encoder; A365 uses Node's global +`fetch`. Encoding-only compression paths are also included as precautionary +hardening, not because the advisory identifies a vulnerable encoder. +Compression behavior and wire formats are unchanged. + +**Updating this package does not update Node.js.** npm engine requirements can +be advisory: application owners must patch the runtime that actually starts +the process, rebuild and redeploy container images, and update hosted or +embedded runtimes through their provider. Disabling browser injection does not +address other runtime vulnerabilities or A365's HTTP transport. + > **Important:** Import and call `useMicrosoftOpenTelemetry()` as early as possible in your application entry point so instrumentations can patch libraries before they are loaded. ### ESM Support -> **Note:** This package requires Node.js 22.0.0 or later. Its ESM loader flow relies on `--import` and `node:module.register()`. For background on why startup ordering matters, see the [OpenTelemetry ESM Support documentation](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md). +> **Note:** Use a patched Node.js version from the [runtime requirements](#nodejs-runtime-requirements). The ESM loader flow relies on `--import` and `node:module.register()`. For background on why startup ordering matters, see the [OpenTelemetry ESM Support documentation](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md). For ESM applications, instrumentation hooks must be registered before any instrumented modules (for example `http`, `express`, `axios`, or loggers) are loaded. This is a fundamental ESM constraint: modules cannot be instrumented after they are already loaded. diff --git a/docs/fabric-getting-started.md b/docs/fabric-getting-started.md index 4e4a9b738..630b34030 100644 --- a/docs/fabric-getting-started.md +++ b/docs/fabric-getting-started.md @@ -22,7 +22,7 @@ Your Node.js app doesn't connect to Fabric directly. Instead, it sends telemetry ## Prerequisites -- [Node.js 22+](https://nodejs.org/) +- Patched [Node.js](https://nodejs.org/): 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x (see [runtime requirements](../README.md#nodejs-runtime-requirements)) - An Azure Data Explorer cluster **or** a [Fabric KQL database](https://learn.microsoft.com/en-us/fabric/real-time-analytics/create-database) — a [free ADX cluster](https://dataexplorer.azure.com/freecluster) works for testing - Azure CLI installed and logged in (`az login`) — used for authentication - The `@microsoft/opentelemetry` npm package (installed in Step 3) diff --git a/package-lock.json b/package-lock.json index fc2a673ff..57ebf864d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,7 +64,7 @@ "vitest": "^4.1.8" }, "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" } }, "node_modules/@azure-rest/core-client": { diff --git a/package.json b/package.json index f61e96d31..78645721e 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ ] }, "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" }, "files": [ "dist/", diff --git a/samples/README.md b/samples/README.md index 87d516073..387df003d 100644 --- a/samples/README.md +++ b/samples/README.md @@ -32,7 +32,7 @@ These sample programs show how to use the `@microsoft/opentelemetry` distributio ## Prerequisites -- [Node.js LTS](https://github.com/nodejs/release#release-schedule) (>= 20.0.0) +- Patched [Node.js](https://nodejs.org/): 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x (see [runtime requirements](../README.md#nodejs-runtime-requirements)) - [TypeScript](https://www.typescriptlang.org/) (install via `npm install -g typescript`) - An [Azure subscription](https://azure.microsoft.com/free/) with an [Application Insights](https://learn.microsoft.com/azure/azure-monitor/app/app-insights-overview) resource diff --git a/samples/agent365-s2s/README.md b/samples/agent365-s2s/README.md index 6b5746cab..b06e7150e 100644 --- a/samples/agent365-s2s/README.md +++ b/samples/agent365-s2s/README.md @@ -7,7 +7,7 @@ required. ## Prerequisites -- Node.js 22 or later. +- Patched Node.js: 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x (see [runtime requirements](../../README.md#nodejs-runtime-requirements)). - An Agent365 blueprint application with a client secret. - An Agent365 agent application in the same Microsoft Entra tenant. - The Agent365 agent application must have the diff --git a/samples/agent365-s2s/package-lock.json b/samples/agent365-s2s/package-lock.json index df9ce6f62..c1c8c1b96 100644 --- a/samples/agent365-s2s/package-lock.json +++ b/samples/agent365-s2s/package-lock.json @@ -18,7 +18,7 @@ "typescript": "^5.6.0" }, "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" } }, "../..": { @@ -81,7 +81,7 @@ "vitest": "^4.1.8" }, "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" } }, "node_modules/@azure/msal-common": { diff --git a/samples/agent365-s2s/package.json b/samples/agent365-s2s/package.json index b580fb159..a7f18b145 100644 --- a/samples/agent365-s2s/package.json +++ b/samples/agent365-s2s/package.json @@ -5,7 +5,7 @@ "type": "module", "description": "Agent365 service-to-service observability sample", "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" }, "scripts": { "build": "npm run clean && tsc -p tsconfig.json", diff --git a/samples/aks-langchain/Dockerfile b/samples/aks-langchain/Dockerfile index c3628c573..b90d409be 100644 --- a/samples/aks-langchain/Dockerfile +++ b/samples/aks-langchain/Dockerfile @@ -1,4 +1,6 @@ -FROM node:22-bookworm-slim +FROM node:22.23.4-bookworm-slim + +RUN node -e "if (process.versions.node !== '22.23.4') throw new Error('Expected Node.js 22.23.4');" ENV NODE_ENV=production \ PORT=3000 diff --git a/samples/aks-langchain/README.md b/samples/aks-langchain/README.md index 3998c8f45..dd5fc6527 100644 --- a/samples/aks-langchain/README.md +++ b/samples/aks-langchain/README.md @@ -20,7 +20,7 @@ be auto-instrumented. ## Prerequisites -- Node.js 22 or later for local runs +- Patched Node.js for local runs: 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x (see [runtime requirements](../../README.md#nodejs-runtime-requirements)) - An Azure subscription with: - an AKS cluster - an Azure Container Registry (ACR) @@ -30,6 +30,12 @@ be auto-instrumented. ## Build and push the image +The Dockerfile pins `node:22.23.4-bookworm-slim` and verifies the runtime before +installing dependencies. Changing the Dockerfile does not patch an already +running pod: rebuild the image and roll out the new image to patch deployed +workloads. Keep the Node.js image pin and its runtime check aligned on future +updates. + Run this command from `samples/aks-langchain`, replacing ``: ```bash diff --git a/samples/aks-langchain/package-lock.json b/samples/aks-langchain/package-lock.json index 209dc3b13..200ed8e31 100644 --- a/samples/aks-langchain/package-lock.json +++ b/samples/aks-langchain/package-lock.json @@ -13,7 +13,7 @@ "@microsoft/opentelemetry": "1.4.0" }, "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" } }, "node_modules/@azure-rest/core-client": { diff --git a/samples/aks-langchain/package.json b/samples/aks-langchain/package.json index 6be1d5f38..3f198387b 100644 --- a/samples/aks-langchain/package.json +++ b/samples/aks-langchain/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" }, "scripts": { "start": "node --import ./telemetry.mjs app.mjs" diff --git a/samples/fabric/README.md b/samples/fabric/README.md index b80fcc380..a36c59501 100644 --- a/samples/fabric/README.md +++ b/samples/fabric/README.md @@ -2,6 +2,9 @@ Express app that sends traces, metrics, and logs to Microsoft Fabric Real-Time Intelligence (or Azure Data Explorer) via an OpenTelemetry Collector. +Use patched Node.js: 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x. +See the [runtime requirements](../../README.md#nodejs-runtime-requirements). + ## How to run ### 1. Start the OTel Collector diff --git a/samples/fabric/package.json b/samples/fabric/package.json index df09f5570..09c10a229 100644 --- a/samples/fabric/package.json +++ b/samples/fabric/package.json @@ -2,6 +2,9 @@ "name": "fabric-demo", "private": true, "type": "module", + "engines": { + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" + }, "scripts": { "start": "OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 node --import @microsoft/opentelemetry/loader app.mjs" }, diff --git a/samples/package-lock.json b/samples/package-lock.json index 65b2399fb..597701945 100644 --- a/samples/package-lock.json +++ b/samples/package-lock.json @@ -26,7 +26,7 @@ "typescript": "~5.9.3" }, "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" } }, "..": { @@ -89,7 +89,7 @@ "vitest": "^4.1.8" }, "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" } }, "node_modules/@cfworker/json-schema": { diff --git a/samples/package.json b/samples/package.json index 8778b7a6d..0a793707b 100644 --- a/samples/package.json +++ b/samples/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "description": "Microsoft OpenTelemetry distribution samples for TypeScript", "engines": { - "node": ">=22.0.0" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" }, "scripts": { "build": "tsc", diff --git a/scripts/check-node-version.cjs b/scripts/check-node-version.cjs new file mode 100644 index 000000000..6afc2fdb4 --- /dev/null +++ b/scripts/check-node-version.cjs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +const requiredNodeVersion = "^22.23.4 || ^24.22.1 || >=26.12.1"; + +function isPatchedNodeVersion(version) { + const match = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(version); + if (!match) { + return false; + } + + const [major, minor, patch] = match.slice(1).map(Number); + const minimum = { 22: [23, 4], 24: [22, 1], 26: [12, 1] }[major]; + return ( + major > 26 || + (minimum !== undefined && (minor > minimum[0] || (minor === minimum[0] && patch >= minimum[1]))) + ); +} + +if (require.main === module) { + if (!isPatchedNodeVersion(process.versions.node)) { + console.error( + `Node.js ${process.versions.node} does not meet the October 21, 2026 security baseline. ` + + `Required: ${requiredNodeVersion}. Upgrade the selected Node.js runtime.`, + ); + process.exitCode = 1; + } else { + console.log(`Node.js ${process.versions.node} meets the October 21, 2026 security baseline.`); + } +} + +module.exports = { isPatchedNodeVersion, requiredNodeVersion }; diff --git a/test/integration/node-version.test.mjs b/test/integration/node-version.test.mjs new file mode 100644 index 000000000..cbbede6b9 --- /dev/null +++ b/test/integration/node-version.test.mjs @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import { readFileSync } from "node:fs"; +import { test } from "node:test"; +import { fileURLToPath } from "node:url"; +import { runInNewContext } from "node:vm"; +import { isPatchedNodeVersion, requiredNodeVersion } from "../../scripts/check-node-version.cjs"; + +test("accepts the October security releases and subsequent stable versions", () => { + for (const version of [ + "22.23.4", + "22.23.5", + "22.24.0", + "24.22.1", + "24.22.2", + "24.23.0", + "26.12.1", + "26.12.2", + "26.13.0", + "27.0.0", + "v22.23.4", + ]) { + assert.equal(isPatchedNodeVersion(version), true, version); + } +}); + +test("rejects vulnerable patches, end-of-life lines, and prereleases", () => { + for (const version of [ + "20.99.99", + "22.0.0", + "22.22.99", + "22.23.3", + "23.99.99", + "24.21.99", + "24.22.0", + "25.99.99", + "26.11.99", + "26.12.0", + "22.23.4-rc.1", + "27.0.0-rc.1", + "", + "22", + "22.23", + "022.23.4", + "not-a-version", + ]) { + assert.equal(isPatchedNodeVersion(version), false, version); + } +}); + +test("checks the running executable, not a supplied version argument or environment override", () => { + const script = fileURLToPath(new URL("../../scripts/check-node-version.cjs", import.meta.url)); + for (const version of ["0.0.0", "99.0.0"]) { + const result = spawnSync(process.execPath, [script, version], { + encoding: "utf8", + env: { ...process.env, NODE_VERSION: version }, + }); + assert.ifError(result.error); + const expected = isPatchedNodeVersion(process.versions.node) ? 0 : 1; + assert.equal(result.status, expected, result.stderr); + assert.ok(`${result.stdout}${result.stderr}`.includes(process.versions.node)); + } +}); + +test("reports failure for an old selected runtime even with patched-version overrides", () => { + const entry = {}; + const errors = []; + const runtime = { + versions: { node: "24.18.0" }, + argv: ["node", "check-node-version.cjs", "24.22.1"], + env: { NODE_VERSION: "24.22.1" }, + }; + const script = readFileSync( + new URL("../../scripts/check-node-version.cjs", import.meta.url), + "utf8", + ); + runInNewContext(script, { + require: { main: entry }, + module: entry, + process: runtime, + console: { + error: (message) => errors.push(message), + log: () => assert.fail("Reported success"), + }, + }); + assert.equal(runtime.exitCode, 1); + assert.match(errors[0], /Node\.js 24\.18\.0 does not meet/); +}); + +test("keeps repository package and linked lockfile runtime requirements aligned", () => { + for (const directory of [ + "", + "samples/", + "samples/agent365-s2s/", + "samples/aks-langchain/", + "samples/fabric/", + ]) { + const manifest = JSON.parse( + readFileSync(new URL(`../../${directory}package.json`, import.meta.url), "utf8"), + ); + assert.equal(manifest.engines.node, requiredNodeVersion, directory || "root"); + if (directory === "samples/fabric/") { + continue; + } + const lock = JSON.parse( + readFileSync(new URL(`../../${directory}package-lock.json`, import.meta.url), "utf8"), + ); + for (const [path, entry] of Object.entries(lock.packages)) { + if (path === "" || path === ".." || path === "../..") { + assert.equal(entry.engines.node, requiredNodeVersion, `${directory}${path}`); + } + } + } +}); From 47e7adbf19a24eb8cd37efbcc591daa014ae6452 Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Fri, 23 Oct 2026 12:39:39 -0700 Subject: [PATCH 2/3] Remove README and contributor guide edits from security patch Also restore the Fabric setup guide to avoid a dangling link to the removed README section. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- CONTRIBUTING.md | 15 ++------------- README.md | 32 +------------------------------- docs/fabric-getting-started.md | 2 +- samples/README.md | 2 +- samples/agent365-s2s/README.md | 2 +- samples/aks-langchain/README.md | 8 +------- samples/fabric/README.md | 3 --- 7 files changed, 7 insertions(+), 57 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7603bc38e..6b5776e90 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,27 +14,17 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope ## Development Setup -1. Install patched [Node.js](https://nodejs.org/): 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x. See the [runtime requirements](README.md#nodejs-runtime-requirements). +1. Install [Node.js](https://nodejs.org/) 22 or later. 2. Install dependencies. 3. Run formatting, linting, and tests before opening a pull request. ```bash -node scripts/check-node-version.cjs npm install npm run build npm run lint npm test ``` -CI pins Node.js 22.23.4 and 24.22.1 and checks `process.versions.node` before -running repository commands. The guard checks the actual executable, not a -version argument or environment override. Its dependency-free regression tests -can be run with `node --test test/integration/node-version.test.mjs`. -Keep runtime pins and package/lockfile engine metadata aligned when updating -the security baseline. GitHub Actions' embedded Node runtimes are managed by -the action/runner providers; `actions/setup-node` only selects the runtime for -subsequent repository commands. - ### Using package-lock.json The committed `package-lock.json` is generated through Microsoft's package proxy. @@ -76,8 +66,7 @@ the required proxy rather than using this workflow to bypass its restrictions. ## SDK performance benchmarks -After building, run the standalone harness on a patched Node.js version from -the [runtime requirements](README.md#nodejs-runtime-requirements). It measures +After building, run the standalone harness on Node.js 22 or later. It measures recording span creation (with and without an attribute), counter aggregation, and log emission through the built SDK. Non-exporting processors and a metric reader keep serialization, network transport, and exporter batching out of the diff --git a/README.md b/README.md index 213e1ccd5..c48502402 100644 --- a/README.md +++ b/README.md @@ -12,41 +12,11 @@ Microsoft OpenTelemetry distribution for Node.js — one import, one call, full npm install @microsoft/opentelemetry ``` -### Node.js runtime requirements - -Use the [October 21, 2026 Node.js security releases](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases) -or a later patched release on your supported Node.js line: - -| Node.js line | Minimum version | -| ------------ | --------------- | -| 22.x | 22.23.4 | -| 24.x | 24.22.1 | -| 26.x | 26.12.1 | - -The package engine range is `^22.23.4 || ^24.22.1 || >=26.12.1`. End-of-life -Node.js 23 and 25 are excluded; future stable majors remain eligible. CI retains -Node.js 22 and 24 coverage. - -This baseline addresses the full advisory, not only the Brotli decoder issue: -DNS, TLS hostname validation, HTTP keep-alive handling, snapshot entropy caches, -permission checks, the Node.js 26 ZIP issue, and the applicable bundled c-ares, -CA certificate, OpenSSL, SQLite, and Undici updates. The SDK's opt-in browser -injection uses Node's Brotli decoder and encoder; A365 uses Node's global -`fetch`. Encoding-only compression paths are also included as precautionary -hardening, not because the advisory identifies a vulnerable encoder. -Compression behavior and wire formats are unchanged. - -**Updating this package does not update Node.js.** npm engine requirements can -be advisory: application owners must patch the runtime that actually starts -the process, rebuild and redeploy container images, and update hosted or -embedded runtimes through their provider. Disabling browser injection does not -address other runtime vulnerabilities or A365's HTTP transport. - > **Important:** Import and call `useMicrosoftOpenTelemetry()` as early as possible in your application entry point so instrumentations can patch libraries before they are loaded. ### ESM Support -> **Note:** Use a patched Node.js version from the [runtime requirements](#nodejs-runtime-requirements). The ESM loader flow relies on `--import` and `node:module.register()`. For background on why startup ordering matters, see the [OpenTelemetry ESM Support documentation](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md). +> **Note:** This package requires Node.js 22.0.0 or later. Its ESM loader flow relies on `--import` and `node:module.register()`. For background on why startup ordering matters, see the [OpenTelemetry ESM Support documentation](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md). For ESM applications, instrumentation hooks must be registered before any instrumented modules (for example `http`, `express`, `axios`, or loggers) are loaded. This is a fundamental ESM constraint: modules cannot be instrumented after they are already loaded. diff --git a/docs/fabric-getting-started.md b/docs/fabric-getting-started.md index 630b34030..4e4a9b738 100644 --- a/docs/fabric-getting-started.md +++ b/docs/fabric-getting-started.md @@ -22,7 +22,7 @@ Your Node.js app doesn't connect to Fabric directly. Instead, it sends telemetry ## Prerequisites -- Patched [Node.js](https://nodejs.org/): 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x (see [runtime requirements](../README.md#nodejs-runtime-requirements)) +- [Node.js 22+](https://nodejs.org/) - An Azure Data Explorer cluster **or** a [Fabric KQL database](https://learn.microsoft.com/en-us/fabric/real-time-analytics/create-database) — a [free ADX cluster](https://dataexplorer.azure.com/freecluster) works for testing - Azure CLI installed and logged in (`az login`) — used for authentication - The `@microsoft/opentelemetry` npm package (installed in Step 3) diff --git a/samples/README.md b/samples/README.md index 387df003d..87d516073 100644 --- a/samples/README.md +++ b/samples/README.md @@ -32,7 +32,7 @@ These sample programs show how to use the `@microsoft/opentelemetry` distributio ## Prerequisites -- Patched [Node.js](https://nodejs.org/): 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x (see [runtime requirements](../README.md#nodejs-runtime-requirements)) +- [Node.js LTS](https://github.com/nodejs/release#release-schedule) (>= 20.0.0) - [TypeScript](https://www.typescriptlang.org/) (install via `npm install -g typescript`) - An [Azure subscription](https://azure.microsoft.com/free/) with an [Application Insights](https://learn.microsoft.com/azure/azure-monitor/app/app-insights-overview) resource diff --git a/samples/agent365-s2s/README.md b/samples/agent365-s2s/README.md index b06e7150e..6b5746cab 100644 --- a/samples/agent365-s2s/README.md +++ b/samples/agent365-s2s/README.md @@ -7,7 +7,7 @@ required. ## Prerequisites -- Patched Node.js: 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x (see [runtime requirements](../../README.md#nodejs-runtime-requirements)). +- Node.js 22 or later. - An Agent365 blueprint application with a client secret. - An Agent365 agent application in the same Microsoft Entra tenant. - The Agent365 agent application must have the diff --git a/samples/aks-langchain/README.md b/samples/aks-langchain/README.md index dd5fc6527..3998c8f45 100644 --- a/samples/aks-langchain/README.md +++ b/samples/aks-langchain/README.md @@ -20,7 +20,7 @@ be auto-instrumented. ## Prerequisites -- Patched Node.js for local runs: 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x (see [runtime requirements](../../README.md#nodejs-runtime-requirements)) +- Node.js 22 or later for local runs - An Azure subscription with: - an AKS cluster - an Azure Container Registry (ACR) @@ -30,12 +30,6 @@ be auto-instrumented. ## Build and push the image -The Dockerfile pins `node:22.23.4-bookworm-slim` and verifies the runtime before -installing dependencies. Changing the Dockerfile does not patch an already -running pod: rebuild the image and roll out the new image to patch deployed -workloads. Keep the Node.js image pin and its runtime check aligned on future -updates. - Run this command from `samples/aks-langchain`, replacing ``: ```bash diff --git a/samples/fabric/README.md b/samples/fabric/README.md index a36c59501..b80fcc380 100644 --- a/samples/fabric/README.md +++ b/samples/fabric/README.md @@ -2,9 +2,6 @@ Express app that sends traces, metrics, and logs to Microsoft Fabric Real-Time Intelligence (or Azure Data Explorer) via an OpenTelemetry Collector. -Use patched Node.js: 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x. -See the [runtime requirements](../../README.md#nodejs-runtime-requirements). - ## How to run ### 1. Start the OTel Collector From bfe19049bba814eb8b0cf6a5886e3b4a19cc5029 Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Fri, 23 Oct 2026 12:46:24 -0700 Subject: [PATCH 3/3] Shorten Node security baseline changelog entry Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c93656b1..0170ffcae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## [Unreleased] ### Bugs Fixed -- Require the full [October 21, 2026 Node.js security baseline](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases): 22.23.4+ on 22.x, 24.22.1+ on 24.x, or 26.12.1+ on 26.x. Pin CI and the AKS sample image, verify the selected runtime, and align sample requirements and lockfile metadata. Include encoding-only compression paths as precautionary hardening without changing compression behavior. Customers must patch and redeploy their Node.js runtimes; upgrading this package alone does not remediate runtime CVEs. +- Require Node.js 22.23.4+, 24.22.1+, or 26.12.1+ on their respective release lines for security fixes. - **Breaking change on Unix (Linux/macOS):** Agent365 offline buffering/replay now requires an explicitly configured, existing, absolute `durableDelivery.storageDirectory`. No automatic Unix temporary-directory fallback or root creation. Missing/invalid roots are logged and disable only disk buffering/replay; online export continues. Customers provision and maintain ownership, permissions (normally a private service-account-owned `0700` root), ACLs, and path-replacement protection; the SDK does not inspect or repair Unix access controls. Windows behavior, explicit-root cache identities, record compatibility, and retention limits are unchanged. Old temporary backlogs are not automatically migrated; see [storage provisioning and migration](A365_DOCUMENTATION.md#storage-provisioning-and-migration). ### Features Added