13261 Commits
Author SHA1 Message Date
Harjoth Khara 1ef43aea16 net,tls: fix session reuse with provided sockets
Preserve literal IP hosts on net.Socket before connection. This keeps
wrapped TLS sessions bound to the correct peer when tls.connect() uses a
provided socket.

Fixes: https://github.com/nodejs/node/issues/64402
Signed-off-by: harjoth <harjoth.khara@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/64430
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-10-28 19:34:49 +00:00
dependabot[bot] 6f249e6af3 tools: bump the eslint group in /tools/eslint with 5 updates
Bumps the eslint group in /tools/eslint with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) | `8.0.6` | `8.0.7` |
| [@babel/eslint-parser](https://github.com/babel/babel/tree/HEAD/eslint/babel-eslint-parser) | `8.0.6` | `8.0.7` |
| [eslint](https://github.com/eslint/eslint) | `10.11.0` | `10.13.0` |
| [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) | `64.5.4` | `65.4.0` |
| [globals](https://github.com/sindresorhus/globals) | `17.12.0` | `17.13.0` |

Updates `@babel/core` from 8.0.6 to 8.0.7
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v8.0.7/packages/babel-core)

Updates `@babel/eslint-parser` from 8.0.6 to 8.0.7
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v8.0.7/eslint/babel-eslint-parser)

Updates `eslint` from 10.11.0 to 10.13.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.11.0...v10.13.0)

Updates `eslint-plugin-jsdoc` from 64.5.4 to 65.4.0
- [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases)
- [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v64.5.4...v65.4.0)

Updates `globals` from 17.12.0 to 17.13.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.12.0...v17.13.0)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-version: 8.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@babel/eslint-parser"
  dependency-version: 8.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: eslint
  dependency-version: 10.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: eslint-plugin-jsdoc
  dependency-version: 65.4.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: eslint
- dependency-name: globals
  dependency-version: 17.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
PR-URL: https://github.com/nodejs/node/pull/67025
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
2026-10-28 15:35:06 +00:00
Yagiz Nizipli c7b1b6207b zlib: grow the output buffer of large async one-shot calls
The asynchronous convenience methods hand the whole input to zlib in
one write, but still take one threadpool round trip per `chunkSize`
(16 KiB by default) of output. Decompressing 4 MiB took 257 round
trips.

Only the concatenated result of these calls is observable, so double
the output buffer whenever it fills up, up to 1 MiB. 4 MiB of output
now takes 10 round trips. The buffer never grows past what is needed
to tell that `maxOutputLength` was exceeded, and results that fit in
the first buffer are unchanged.

Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: Grok
PR-URL: https://github.com/nodejs/node/pull/66863
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-10-28 13:57:21 +00:00
Yagiz Nizipli cbe558587f zlib: finish async convenience calls in one write
The asynchronous convenience methods (`zlib.deflate()`,
`zlib.inflate()`, `zlib.gunzip()`, ...) wrote the input to a
Transform stream and then ended it. That took two threadpool round
trips, one for the data and one for the final flush, and ran the
result through the stream machinery.

The whole input is known up front, so unless `info` or a custom
`flush` is requested, process it with the finish flush directly, the
way the synchronous methods already do, and collect the output in the
write callback. A call whose output fits in one buffer now takes a
single threadpool round trip. The output is unchanged: the previous
two-write sequence already produced the same bytes as the synchronous
methods. `zstdCompress()` keeps the separate end-of-frame write,
because a single `ZSTD_e_end` call can produce slightly larger frames.

benchmark/compare.js, 40 runs, n=100000:

                                          confidence  improvement
    zlib/inflate.js method='inflate'      ***          +94.91 %
    zlib/deflate.js method='deflate'      ***          +66.27 %

Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: Grok
PR-URL: https://github.com/nodejs/node/pull/66863
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-10-28 13:57:17 +00:00
Yagiz Nizipli 0160710ceb zlib: skip the stream in sync convenience calls without options
`zlib.inflateSync(buffer)` and the other synchronous convenience
methods constructed a Transform stream for every call, even though
only its native handle is used and, without options, the stream is
never exposed. They also allocated a fresh output chunk for every
call.

When no options are passed, drive a native handle created with the
default settings directly, and decompress into a scratch buffer kept
between calls, copying the result out. Calls with options, including
`info`, keep the existing path. Results and errors are unchanged.

Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: Grok
PR-URL: https://github.com/nodejs/node/pull/66864
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-10-28 13:56:55 +00:00
Huang-404-Q 663f666fda http2: clear the session timeout before marking it destroyed
closeSession() set SESSION_FLAGS_DESTROYED and then called
session.setTimeout(0). setStreamTimeout() returns early when the
session is destroyed, so the idle timer stayed armed and retained
the session until the server timeout fired.

Clear the timeout and remove its listeners before setting the
destroyed flag.

Fixes: https://github.com/nodejs/node/issues/66885
Signed-off-by: huang <13165998033@163.com>
PR-URL: https://github.com/nodejs/node/pull/66886
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-10-28 13:31:19 +00:00
Guy Bedford ec7a28f2e0 module: cache compiled WebAssembly modules in the compile cache
Extends the module compile cache to WebAssembly modules loaded through
the ES module integration. A new kWasm entry type is keyed on the module
URL with the wire bytes as the hashed source, and stores the serialized
CompiledWasmModule. On load, cached code is deserialized through
v8::WasmModuleCompilation with the same compile options the translator
uses (js-string builtins and imported string constants), falling back
to compilation when V8 rejects it.

As for JavaScript, the cache entry is generated right after compilation.
V8 only serializes optimized tier code, so with the default lazy
baseline compilation there is nothing to cache and no entry is written;
a complete cache requires --no-liftoff --no-wasm-lazy-compilation, which
is documented as the way to use the compile cache for WebAssembly.

Signed-off-by: Guy Bedford <guybedford@gmail.com>
Assisted-by: Claude Code
PR-URL: https://github.com/nodejs/node/pull/66191
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-10-28 01:46:44 +00:00
Philipp Dunkel 7622ebb3d7 zlib: add raw content read methods to ZipEntry
zipEntry.rawContent was a getter that exposed the retained buffer of an
in-memory entry and returned null for a file-backed or streaming one,
so the still-compressed bytes of a member read through ZipFile could
not be obtained at all.

Replace it with rawContent(), rawContentSync() and
rawContentIterator(), which mirror content(), contentSync() and
contentIterator() but return the bytes as stored, without
decompressing or verifying them. They work for every entry that has
readable content, return caller-owned buffers from the buffered
variants, and accept a maxSize bound on the compressed size.

Signed-off-by: Philipp Dunkel <pip@pipobscure.com>
PR-URL: https://github.com/nodejs/node/pull/66801
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-10-27 17:45:32 +00:00
Ved Chaudhari 98dbf6070e events: report original once() listener on removal
When a `once()` listener is removed, emit the original user-defined
function in the `removeListener` event instead of the internal wrapper,
matching the behavior of the single-listener path.

Assisted-by: claude:opus-5.5
Signed-off-by: vedchaudhari <vedc2853@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66621
Refs: https://github.com/nodejs/node/issues/5551
Refs: https://github.com/nodejs/node/pull/6394
Refs: https://github.com/nodejs/node/pull/33596
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
2026-10-27 10:58:13 +00:00
Filip Skokan a2cd8aa883 crypto,https,tls: end OpenSSL engine support
OpenSSL removed support for engines in version 4. Remove the Node.js
APIs, constants, native bindings, and implementation that depend on
ENGINE.

Keep recognizing the former TLS and HTTPS engine options so their use
fails explicitly instead of appearing to work while being ignored.

Move DEP0183 directly from Documentation-only to End-of-Life after
reverting its unreleased Runtime deprecation.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/64777
Fixes: https://github.com/nodejs/node/issues/56733
Refs: https://github.com/nodejs/node/pull/64211
Refs: https://github.com/nodejs/node/pull/63966
Refs: https://github.com/nodejs/node/pull/53329
Refs: https://github.com/nodejs/node/pull/48950
Refs: https://github.com/nodejs/node/issues/45465
Refs: https://github.com/nodejs/node/issues/42827
Refs: https://github.com/nodejs/node/issues/47076
Refs: https://github.com/nodejs/node/pull/62862
Refs: https://github.com/nodejs/node/pull/38512
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-25 22:36:38 +01:00
Filip Skokan b61e682fc0 Revert "crypto,https,tls: runtime-deprecate OpenSSL engine-based APIs (DEP0183)"
This reverts commit da516920fc.

PR-URL: https://github.com/nodejs/node/pull/64777
Fixes: https://github.com/nodejs/node/issues/56733
Refs: https://github.com/nodejs/node/pull/64211
Refs: https://github.com/nodejs/node/pull/63966
Refs: https://github.com/nodejs/node/pull/53329
Refs: https://github.com/nodejs/node/pull/48950
Refs: https://github.com/nodejs/node/issues/45465
Refs: https://github.com/nodejs/node/issues/42827
Refs: https://github.com/nodejs/node/issues/47076
Refs: https://github.com/nodejs/node/pull/62862
Refs: https://github.com/nodejs/node/pull/38512
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-25 22:36:37 +01:00
Filip Skokan fb8d52d75a crypto: move DEP0093 to End-of-Life
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/64777
Fixes: https://github.com/nodejs/node/issues/56733
Refs: https://github.com/nodejs/node/pull/64211
Refs: https://github.com/nodejs/node/pull/63966
Refs: https://github.com/nodejs/node/pull/53329
Refs: https://github.com/nodejs/node/pull/48950
Refs: https://github.com/nodejs/node/issues/45465
Refs: https://github.com/nodejs/node/issues/42827
Refs: https://github.com/nodejs/node/issues/47076
Refs: https://github.com/nodejs/node/pull/62862
Refs: https://github.com/nodejs/node/pull/38512
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-25 22:36:36 +01:00
Christian Aurich Zanettini Martins c7ae7ab5b9 vfs: fix readlink, realpath and mkdtemp encoding
On a mounted VFS, `readlink()`, `realpath()` and `mkdtemp()` only
returned a Buffer for `{ encoding: 'buffer' }`. The string form
`'buffer'`, any other encoding, and a Buffer `mkdtemp()` prefix were
ignored. The `VirtualFileSystem` `readlink` and `realpath` methods
ignored the encoding with `MemoryProvider` and passed it on to
`RealFSProvider`, which threw `ERR_INVALID_ARG_TYPE` for `'buffer'`,
while for other encodings `realpath()` failed and `readlink()`
returned the host path of absolute targets.

Get these paths from the provider as strings and apply the encoding
to the result, normalizing the options with `getOptions()` and
converting with `encodeRealpathResult()` as `fs` does. The latter
moves to `internal/fs/utils` so the VFS can use it.

Signed-off-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66352
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-10-25 17:19:12 +00:00
Matteo Collina 60e6c84f4e stream: keep async context of parked writes
A TransformStream write that parks on backpressure was resumed from
the read that lifted the backpressure, so transform(), the writes
queued behind it, and flush() ran in the reader's async context
instead of the writer's. Capture the async context frame when the
write parks and restore it while the continuation runs, matching the
context the spec's [[backpressureChangePromise]] reaction had.

Fixes: https://github.com/nodejs/node/issues/66906

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66907
Fixes: https://github.com/nodejs/node/issues/66906
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-10-25 12:10:11 +00:00
Filip Skokan a0b4170764 tls: configure TLS 1.3 ciphers with BoringSSL
Translate cipher-suite names into protocol IDs for BoringSSL's TLS 1.3
configuration API. Handle duplicates and unknown names, reject nonempty
lists without a supported suite, and implement honorCipherOrder through
preference flags.

Cover suite restrictions, explicit preference ordering, legacy-only
lists, runtime defaults, and command-line overrides.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66922
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-10-24 22:04:15 +00:00
Filip Skokan 7e58295439 crypto: wire up SHA-3 with BoringSSL
Add SHA3-256, SHA3-384, and SHA3-512 to name lookup and getHashes().
BoringSSL exposes EVP_sha3_* descriptors but omits them from its
digest registry. Map the names directly to those descriptors so
node:crypto can use them too.

When using BoringSSL, limit WebCrypto SHA-3 support to digest
operations.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66922
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-10-24 22:04:14 +00:00
Robert Nagy 6dea43a0f8 lib: speed up AbortSignal
Speed up creating and aborting signals, adding and removing abort
listeners, AbortSignal.any() and AbortSignal.timeout(), and stop the
default abort reason from retaining the aborting caller.

- Only allocate and dispatch the abort event when the signal has abort
  listeners, and only allocate the dependent signal list when there
  are dependent signals.
- Track whether an event is trusted with a private field instead of a
  WeakSet.
- Flatten addEventListener() options into locals instead of
  allocating a normalized options object, only validate the signal
  option when one is passed, and use the listener flags directly.
- Call the EventTarget kNewListener and kRemoveListener
  implementations directly. V8 does not optimize keyed super property
  access such as super[kNewListener]().
- Initialize the internal slots that AbortSignal.any() adds to its
  sources up front, and the composite-only slots for composites, so
  live signals don't change shape.
- Give every signal a single WeakRef that is shared by all the
  composites that follow it, and register each composite and each
  source once with their cleanup registries instead of registering
  every (source, composite) pair with an unregister token. Registering
  with an unregister token is several times more expensive.
- Register AbortSignal.timeout() timers through a holder that is
  emptied when the timer fires, instead of using the signal as an
  unregister token.
- Take positional arguments in AbortSignal's internal constructor
  instead of destructuring an options object that defaults to
  kEmptyObject. kEmptyObject is a null-prototype object, which V8 keeps
  in dictionary mode, so each of those reads was an uncached dictionary
  miss that cost more than the rest of the constructor.
- Create the default abort reason with Error.stackTraceLimit set to 0.
  Until a captured stack is formatted, V8 keeps the call sites, which
  retain the receivers and functions of the aborting caller's frames,
  so a retained signal kept the aborted work alive. Formatting the
  stack eagerly would fix that but costs several microseconds per
  abort(). The default AbortError no longer shows where abort() was
  called; callers that want that can pass their own reason.
- Add benchmarks for aborting, adding and removing abort listeners,
  and AbortSignal.any().

Refs: https://github.com/nodejs/node/issues/66192
Refs: https://github.com/nodejs/node/pull/66265
Assisted-by: claude:opus-5.5
Signed-off-by: Robert Nagy <ronagy@icloud.com>
PR-URL: https://github.com/nodejs/node/pull/66789
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2026-10-24 19:17:24 +00:00
Mert Can Altin 6353f4026c lib: optimize TextEncoder.encode for short strings
Assisted-by: Claude opus 5.5
Signed-off-by: Mert Can Altin <mertgold60@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66831
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
2026-10-23 07:51:50 +00:00
joao-oliveira-softtor 45b6626457 test_runner: add option to forbid exclusive tests
Add --test-forbid-only and the forbidOnly run() option to detect
accidentally committed exclusive tests. Reject only declarations and
runOnly(true) in both isolation modes, and record a run-level failure
so TODO and expected failures cannot absorb the error.

Document the runtime-only detection and add regression coverage for
filtering, option inheritance, both isolation modes, and disabled
guards.

Refs: https://github.com/nodejs/node/issues/60917
Assisted-by: a coding agent
Signed-off-by: João Victor <joao.oliveira@softtor.com.br>
PR-URL: https://github.com/nodejs/node/pull/66578
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
2026-10-23 07:04:37 +00:00
Trivikram Kamat fcb1aa83f6 vfs: fix promises.watch() with an already-aborted signal
fs.promises.watch() over a virtual mount resolved the first next()
with { done: true } when the signal was already aborted, while native
fs.promises.watch() rejects with ABORT_ERR.

Buffer the AbortError in VFSWatchAsyncIterable so the first next()
rejects once and later calls behave like an exhausted iterator,
matching the native async generator. Concurrently pending next()
calls now resolve after the rejecting one instead of all rejecting.

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: opencode
PR-URL: https://github.com/nodejs/node/pull/66254
Fixes: https://github.com/nodejs/node/issues/66253
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-10-22 22:27:46 +00:00
Trivikram Kamat 44d5d57ad2 vfs: keep open memory handles in sync with file
A MemoryFileHandle snapshotted the file's buffer at open and never
checked the entry again. After the file changed through the provider
or another handle, an open handle served stale reads and fstat sizes,
and its writes went into the old copy, undoing other handles' changes.

Record the entry content each handle last saw or wrote, and adopt the
entry's content whenever another handle has replaced it, so an open
descriptor is a live view of the file as on a real filesystem.

Signed-off-by: Trivikram Kamat <16024985+trivikr@users.noreply.github.com>
Assisted-by: claude:opus-5.5
PR-URL: https://github.com/nodejs/node/pull/66356
Fixes: https://github.com/nodejs/node/issues/66355
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-10-22 21:49:15 +00:00
Efe Karasakal 53f037ecc3 quic: remove obsolete setOutbound()
Signed-off-by: Efe Karasakal <hi@efe.dev>
PR-URL: https://github.com/nodejs/node/pull/66646
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-22 13:38:41 +00:00
Filip Skokan 8c44e38dc6 crypto: reset random caches across snapshots
Startup snapshots retain unused randomInt() and UUID cache entries,
causing deserialized processes to replay the same random values.

Clear the caches after user serialization callbacks and before user
deserialization callbacks. The latter also handles caches refilled by
microtasks, next ticks, or exit handlers after serialization callbacks.

Refs: https://hackerone.com/reports/4059814
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs-private/node-private/pull/987
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ruy Adorno <ruy@vlt.sh>
CVE-ID: CVE-2026-106074
2026-10-21 12:57:43 +02:00
RafaelGSS 6b88896652 permission: check permission model in realpathSync
The equivalent entry points (fs.realpathSync.native(),
fs.promises.realpath(), fs.lstatSync(), fs.existsSync())
already deny access for the same paths

Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
PR-URL: https://github.com/nodejs-private/node-private/pull/973
Refs: https://hackerone.com/reports/3838675
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
CVE-ID: CVE-2026-106073
2026-10-21 12:57:43 +02:00
Matteo Collina c5f5cb5b96 zlib: avoid caching invalid ZIP local headers
The lazy file-backed ZIP resolver cached a parsed local header before
checking it against the central directory. A failed check therefore left
the entry with a cached header and unresolved content offset, allowing a
later read to use the file descriptor's current position.

Validate the local header and calculate its content offset before
committing either value to the entry.

Assisted-by: Pi
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs-private/node-private/pull/981
Refs: https://hackerone.com/reports/4004290
Reviewed-By: Robert Nagy <ronagy@icloud.com>
CVE-ID: CVE-2026-106070
2026-10-21 12:57:43 +02:00
Matteo Collina 9ccbc81ece tls: reject non-canonical IP addresses
TLS identity checks normalized non-canonical numeric hosts before
matching certificates. Platform resolvers can interpret the original
host as a different address.

Reject hosts that become IP addresses only after domainToASCII()
normalization.

Assisted-by: Pi
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs-private/node-private/pull/982
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
CVE-ID: CVE-2026-106069
CVE-ID: CVE-2026-106072
2026-10-21 12:57:43 +02:00
James M Snell 9731991b3c tls: fix ip normalization regression
The regression is a low-severity bug that's not easy to
exploit. Basically it just means the hostname check can
be bypassed.

Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs-private/node-private/pull/985
Fixes: https://hackerone.com/reports/4038287
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
CVE-ID: CVE-2026-105483
2026-10-21 12:57:42 +02:00
James M Snell a370966282 dns: validate resolve inputs for null bytes
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs-private/node-private/pull/984
Fixes: https://hackerone.com/reports/4038342
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
CVE-ID: CVE-2026-105482
2026-10-21 12:57:35 +02:00
Matteo Collina 6698675526 test_runner: use AsyncLocalStorage instead of async_hooks
Track the test that owns the current async context with an
AsyncLocalStorage instead of a createHook() init/destroy map.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66795
Refs: https://github.com/nodejs/node/pull/61030
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2026-10-20 14:00:22 +00:00
Philipp Dunkel df2ea49e00 zlib: add crc32c
Add zlib.crc32c(data[, value]), which computes the CRC-32C checksum
(Castagnoli polynomial, RFC 3720 section 12.1). CRC-32C has better
error detection properties than the CRC-32 of zlib.crc32() and is the
checksum required by many current protocols, formats and services,
among them:

- iSCSI header and data digests (RFC 7143)
- SCTP packet checksums (RFC 9260)
- iWARP MPA framing (RFC 5044)
- NVMe/TCP header and data digests
- ext4, Btrfs and XFS metadata checksums
- the Snappy framing format
- Apache Kafka record batches
- LevelDB and RocksDB block checksums
- TensorFlow TFRecord files
- Google Cloud Storage and Amazon S3 object checksums

Implementing any of these in JavaScript currently needs a userland
CRC-32C, which is far slower than native code.

The function mirrors zlib.crc32(): it accepts a string (encoded as
UTF-8) or an ArrayBufferView, takes an optional 32-bit unsigned
starting value so a checksum can be continued across chunks, and has a
V8 fast API path.

The checksum is computed by absl::ExtendCrc32c() from the bundled
Abseil, which is already built and linked into node, so this adds no
new dependency and no new checksum implementation. absl_crc32c is
added to the libraries linked with --shared-abseil.

Abseil selects its hardware-accelerated CRC-32C path (SSE4.2 and
PCLMULQDQ on x64, the CRC32 and PMULL extensions on arm64) at compile
time, so with node's default compiler flags the portable table-driven
implementation is used. It runs at about the same speed as zlib.crc32()
(about 6.5 GB/s on a recent x64 machine), while the hardware path
reaches about 38 GB/s. Builds whose target CPU baseline already
includes those instructions get the hardware path without changes.
Enabling it for generic builds is left out on purpose: on x64, Abseil
uses the accelerated code for unrecognized CPUs without a runtime
feature check, so compiling it in unconditionally would fault on CPUs
without SSE4.2.

Signed-off-by: Philipp Dunkel <pip@pipobscure.com>
PR-URL: https://github.com/nodejs/node/pull/66828
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-10-20 12:33:08 +00:00
Donghoon Kang 531d28fc36 util: fix inspecting URL subclass prototypes
Check the URL private field brand before accessing href to avoid
throwing when inspecting URL subclass prototypes.

Assisted-by: Codex:6.1SolHigh
Signed-off-by: HoonDongKang <d159123@naver.com>
PR-URL: https://github.com/nodejs/node/pull/66822
Fixes: https://github.com/nodejs/node/issues/66821
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
2026-10-20 04:54:54 +00:00
Efe Karasakal 107133ceb8 quic: allow null body when opening streams
Signed-off-by: Efe Karasakal <hi@efe.dev>
PR-URL: https://github.com/nodejs/node/pull/66690
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-10-19 21:16:23 +00:00
Guy Bedford 8ae0ad0683 module: add "worker" condition for Web Worker threads
Adds a "worker" package condition that is applied within Web Worker
threads created via the `Worker` global, for the worker entry point,
its dependencies, `import()`, `require()` and `import.meta.resolve()`.
Threads created via `worker_threads`, including from within a Web
Worker, do not apply the condition. Other conditions are unaffected.

Assisted-by: OpenCode
Signed-off-by: Guy Bedford <guybedford@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66635
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-10-19 17:09:42 +00:00
Marco Ippolito 2052d0dcdf module: add --experimental-strip-private-modules
Signed-off-by: Marco Ippolito <marcoippolito54@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63869
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Pietro Marchini <pietro.marchini94@gmail.com>
2026-10-19 13:03:51 +00:00
Tim Perry 135b70e670 tls: add tlsSocket.socket, to access the raw stream beneath TLS
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66598
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
2026-10-19 12:35:59 +00:00
Efe Karasakal 6678d6f71d quic: reuse header support assertion
Signed-off-by: Efe Karasakal <hi@efe.dev>
PR-URL: https://github.com/nodejs/node/pull/66777
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-10-19 12:35:33 +00:00
Marco 1a885caa6e fs: add mkstemp()
Add fs.mkstemp(), fs.mkstempSync() and fsPromises.mkstemp(), which
create and open a unique temporary file in one operation. They expose
uv_fs_mkstemp(), the file counterpart of the function behind
fs.mkdtemp().

The callback and sync versions return the path and a file descriptor,
the promise version returns the path and a FileHandle.

libuv clears the path of the request when mkstemp() fails, so the
template is saved in the request and used for the path of the error.

The functions are also supported on mounted virtual file systems.

Refs: https://github.com/nodejs/node/pull/33549
Refs: https://github.com/nodejs/node/issues/33890
Refs: https://github.com/nodejs/node/issues/5332
Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66484
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-19 02:34:09 +00:00
Harjoth Khara 06550c777f vfs: enforce readonly state on open handles
Signed-off-by: harjoth <harjoth.khara@gmail.com>
Fixes: https://github.com/nodejs/node/issues/64401
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/64403
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-10-19 01:41:35 +00:00
Matteo Collina 9a9f7e87b8 process: return unregister fn from finalization
process.finalization.register() and registerBeforeExit() now return
a function that removes only that registration, leaving other
registrations for the same object in place. The function does not
hold a strong reference to the object.

Each registration now uses its WeakRef as the unregister token, which
also makes process.finalization.unregister() remove the entries from
the FinalizationRegistry; previously it passed the object as the
token, which was never registered, so the call had no effect.

Refs: https://github.com/nodejs/node/pull/66482

Signed-off-by: Matteo Collina <matteo.collina@gmail.com>
Assisted-by: pi
PR-URL: https://github.com/nodejs/node/pull/66482
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
2026-10-18 06:36:43 +00:00
Efe Karasakal f88a1d25e9 quic: validate stream error codes
Assisted-by: Codex
Signed-off-by: Efe Karasakal <hi@efe.dev>
PR-URL: https://github.com/nodejs/node/pull/66650
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-10-17 21:42:53 +00:00
Matteo Collina c526694ae9 module: fix require(esm) on the module.register() hooks thread
On the async loader hooks thread, resolve kImportInRequiredESM and
kRequireInImportedCJS requests synchronously again, and always use
ModuleJobSync for kImportInRequiredESM. Otherwise require() of an ES
module with imports from a hooks module hit an internal assertion in
ModuleJobSync.syncLink().

Fixes: https://github.com/nodejs/node/issues/66767
Refs: https://github.com/nodejs/node/pull/62530
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66770
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2026-10-17 16:26:39 +00:00
Matteo Collina 269cab6320 net: fail closed when BlockList peer address is unavailable
When a net.Server is configured with a `blockList`, the peer address is
looked up with getpeername() and checked before the connection is
accepted. If the peer address cannot be obtained (for example, the
connection was reset before getpeername(), causing
uv_tcp_getpeername() to return ENOTCONN), the access-control check was
silently skipped and the connection proceeded, allowing a blocked peer
to reach the application's 'connection' handler (fail open).

Fail closed: when a BlockList is configured but the peer address cannot
be determined, close the connection instead of bypassing the check. A
connection whose peer address cannot be obtained cannot be proven to be
allowed, so it must be refused.

Ref: https://github.com/nodejs/node/issues/66422
Ref: https://github.com/libuv/libuv/pull/5337

Signed-off-by: Matteo Collina <hello@matteocollina.com>
Assisted-by: pi
PR-URL: https://github.com/nodejs/node/pull/66640
Refs: https://github.com/nodejs/node/issues/66422
Refs: https://github.com/libuv/libuv/pull/5337
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-10-17 09:45:08 +00:00
Matteo Collina 4e75b714df stream: trim TransformStream construction costs
Constructing a TransformStream allocated five closures for the sink and
source algorithms of its two sides, and each side adopted the start
promise through a wrapper promise plus a thenable job, so a stream
without a start() left about three kilobytes pending in the microtask
queue until the started steps ran. Per-stream creation bursts spend
most of their time copying that graph through the scavenger.

The sink and source algorithms are now shared functions that reach the
transform stream through a field on their controller state (the
controller is passed to the close, abort and cancel algorithms for
that), and the post-start steps of both sides are delivered by one
reaction chain on a shared promise, taking the same microtask hops as
the spec's start promise adoption: three after construction for a
non-thenable start result, two after the adopting promise settles for a
thenable one. The readable and writable transfer state records are
materialized on first transfer instead of per stream.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66643
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2026-10-17 06:20:05 +00:00
Rafael Gonzaga 62ca1bae5a vfs: allow mounting in permission audit mode
Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
PR-URL: https://github.com/nodejs/node/pull/66745
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-17 00:53:49 +00:00
Guilherme Araújo f513ec7e7c test_runner: add mockReturnValue and promise helpers
Add mockReturnValue(), mockResolvedValue() and mockRejectedValue()
to MockFunctionContext as shorthands for common mockImplementation()
patterns.

Signed-off-by: Guilherme Araújo <arauujogui@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66631
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
2026-10-16 18:06:44 +00:00
Roberto Bianchi f59539b514 url: skip plain prefixes in percent-escape checks
decodeFormComponent() already finds the first percent character, but
hasPercentHex() scans the plain prefix again. Start the check at the
known position to avoid repeating that work.

Replacing plus signs with spaces preserves character positions, so
escape validation and decoding behavior remain unchanged.

Signed-off-by: Roberto Bianchi <roberto.bianchi@spendesk.com>
PR-URL: https://github.com/nodejs/node/pull/66696
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-16 16:59:40 +00:00
Philipp Dunkel 9f2fb935fd sea: mount vfsArchive at layer 0 and in workers
A single executable application built with "vfsArchive" mounted its
archive at the next free layer, like any file system a program mounts
itself, and only in the main thread. A worker had no mount at all, so
a path into the archive, such as the main script's __filename, could
not be loaded there.

Mount the archive at the layer reserved for --vfs-load instead, so it
is at the same mount point in every thread, and mount it in each
worker as well, with the main script placed at its root just as in
the main thread. The worker reads the main script through a new
getMainCode() binding, since no main script is handed to it. Unlike
the --vfs-load source, the archive needs no provider that a preload
could register, so its mount in a worker is not deferred past
--import.

Since the archive takes that mount point, reject --vfs-load alongside
it: --build-sea refuses it in "execArgv", and the executable refuses it
at startup when it comes from --node-options or from the execArgv of a
worker.

Also fix the example in vfs.md, which showed a file system a program
mounts itself at layer 0, the layer reserved for these mounts.

Signed-off-by: Philipp Dunkel <pip@pipobscure.com>
PR-URL: https://github.com/nodejs/node/pull/66709
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-16 12:44:35 +00:00
James M Snell 153ec89621 stream: make stream/iter from() cancellation waits cheaper
To stay cancellable while a source is pending, from() waits for every
value of an async source through waitForNormalization(). For each value
it created a PromiseWithResolvers(), raced it against the value with
SafePromiseRace(), which wraps both in new promises, and ran an async
function with try/finally. This was the largest per-batch cost of
normalizing an async source.

Wait with a single promise and a single reaction on the value instead,
and reject that promise directly on cancellation. The outcome is
unchanged: the value's result, its rejection, or the cancellation
reason, whichever comes first, and the cancellation reason if the
normalization was cancelled by the time the value fulfills.

With an async generator yielding 16-byte chunks, pipeTo() is about
1.7x faster and iterating from() about 1.75x faster.

Assisted-by: OpenCode
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66648
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-15 13:26:52 +00:00
James M Snell 818f34833a stream: share the once option for stream/iter abort listeners
stream/iter registered its one-time 'abort' listeners with a new
`{ __proto__: null, once: true }` options object every time, which can
be once per chunk (abortableNext()) or per waiting write. Use a single
shared kNullOnceOption instead. It is frozen, because signals can come
from user code and a patched addEventListener() must not be able to
change the options for every later registration.

The difference is small, since the listener registration itself costs
much more: with 300,000 16-byte chunks, pull() with a signal is about
1.7% faster, push() writes that wait with a signal about 3% faster, and
pipeTo() and bytes() with a signal are unchanged.

Assisted-by: OpenCode
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66648
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-15 13:26:51 +00:00
James M Snell 17e7b68996 stream: do not miss 'drain' in fromWritable()
When a write filled the classic Writable, fromWritable() recorded that
it needed to drain, but only listened for 'drain' once a later write
was queued or something waited for drain. If the Writable emitted
'drain' before that, for example because its write callback ran on a
microtask or with process.nextTick(), the event was missed and the flag
was never cleared: the next write() or writev() never settled, canWrite
stayed false and ondrain() never resolved.

Listen for 'drain' as soon as a write returns false, and keep listening
until it is emitted.

Assisted-by: OpenCode
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66648
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-15 13:26:50 +00:00