Commit Graph
13144 Commits
Author SHA1 Message Date
Donghoon Kang 617e082ff2 ffi: accept safe integer numbers for 64-bit arguments
Allow safe integer numbers as int64 and uint64 arguments alongside
bigint values. Reject negative numbers for uint64 and numbers outside
the safe integer range. Keep 64-bit return values as bigint.

Apply validation and conversion across the Fast API, shared-buffer,
and generic argument conversion paths.

Add coverage for Number and BigInt boundaries, invalid inputs, and
single-argument calls before and after optimization.

Signed-off-by: HoonDongKang <d159123@naver.com>
Assisted-by: Codex:Astra-medium
PR-URL: https://github.com/nodejs/node/pull/66197
Fixes: https://github.com/nodejs/node/issues/66198
Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2026-10-03 09:51:13 +00:00
Matteo Collina b933d20c3f http: avoid dictionary-mode objects in responses
`setHeader()` stored headers in a `{ __proto__: null }` literal and
`OutgoingMessage` let EventEmitter create the same literal for its
listener table. V8 creates null-prototype literals in dictionary mode,
so every response paid for a hash table allocation on the first
`setHeader()`/`on()` call and for dictionary lookups on every header
access, including the `for...in` in `_storeHeader()`.

Use a fast-mode object with an empty null-prototype chain for the
headers, and preset the listener table with the common events, as
streams already do.

Hello-world server (`res.setHeader()` + `res.end()`), one core:
40.9k -> 50.0k req/s (+22%); CPU 24.4 -> 20.0 us/req; 4374 -> 3905 B
of young-gen allocation per request. Responses are byte-identical.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66420
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
2026-10-03 09:50:37 +00:00
Miodrag Obradovic 1ee5d29c75 util: fix inspect indentation of detached DataView
formatExtraProperties() raised ctx.indentationLvl before reading the
property. The getters of a detached DataView throw, so the level was
never lowered again, and the DataView and everything inspected after it
in the same call ended up indented too far. Read the value first.

Signed-off-by: Miodrag Obradovic <mck097@gmail.com>
Assisted-by: a closed-source coding agent
PR-URL: https://github.com/nodejs/node/pull/66421
Refs: https://github.com/nodejs/node/pull/60131
Reviewed-By: Jordan Harband <ljharb@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
2026-10-03 09:50:25 +00:00
Mert Can Altin 52b68e01a0 crypto: improve random synchronous number generation performance
Instead of creating a RandomBytesJob object, it calls CSPRNG()
directly now.

Assisted-by: Claude Code
Signed-off-by: Mert Can Altin <mertgold60@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66348
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-10-03 08:32:22 +00:00
Matteo Collina 984aa0c25e async_hooks: remove legacy AsyncLocalStorage implementation
Remove the async_hooks-based AsyncLocalStorage fallback and the
--no-async-context-frame flag, making AsyncContextFrame the sole
implementation.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/63641
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
2026-10-03 06:41:28 +00:00
Trivikram Kamat 2bcc5dd2ee ffi: remove permission checks from dlclose and dlsym
The docs describe `ffi.dlclose(handle)` and `ffi.dlsym(handle, symbol)`
as equivalent to `handle.close()` and `handle.getSymbol(symbol)`, but
only the functions called `checkFFIPermission()`. After
`process.permission.drop('ffi')`, `ffi.dlclose(lib)` threw
`ERR_ACCESS_DENIED` while `lib.close()` succeeded.

Remove the checks so the functions defer to the handle. Permission is
already checked when the `DynamicLibrary` is constructed, and dropping
a permission does not revoke resources that are already open.

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/66426
Fixes: https://github.com/nodejs/node/issues/66425
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2026-10-03 05:29:33 +00:00
Jungwon Sohn 4791219541 module: centralize builtin exposure policies
Keep scheme-only and option-gated builtin exposure rules in the
JavaScript loader. Leave option registration and code-cache
categorization with their native owners.

Assisted-by: Codex
Signed-off-by: sjungwon03 <sjungwon03@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66292
Refs: https://github.com/nodejs/node/pull/65418
Refs: https://github.com/nodejs/node/pull/65964
Refs: https://github.com/nodejs/node/pull/65920
Refs: https://github.com/nodejs/node/pull/65840
Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com>
2026-10-02 17:29:27 +00:00
Matteo Collina 4486dce709 process: use a class for nextTick resources
The resource created for each `process.nextTick()` call was an object
literal with three computed symbol keys. V8 builds such literals from a
boilerplate that only covers the static keys, so the symbol-keyed
properties end up in a separate property array allocated per tick, and
each computed-key store goes through the runtime.

Construct the resource through a class instead, so that every tick
object shares one map with all five fields in-object.

process/next-tick-breadth-args.js: ~1.58M -> ~1.95M ops/s (+23%).

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66415
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2026-10-02 14:45:34 +00:00
Muhammad Faizan Uddin 21090da0cf test_runner: do not crash on stdout that mimics a v8 frame
The child test process sends framed report messages and raw user stdout
over one pipe, using the bytes FF 0F to mark the start of a frame. User
output can contain those same bytes, so #processRawBuffer could read a
plausible size from stray stdout and hand the bytes to the v8
deserializer. The deserializer then threw. Because the call had no error
handling, the exception aborted the whole test run.

Read the frame before advancing the buffer and wrap the deserialize in a
try/catch. When the read fails, leave the buffer untouched and stop
parsing frames so #drainRawBuffer emits the stray byte as stdout and
rescans for the next real header. This turns a fatal crash into
recoverable stdout and preserves any real frames that follow the stray
bytes.

Fixes: https://github.com/nodejs/node/issues/66164
Signed-off-by: Muhammad Faizan Uddin <faizan.uddin94@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66273
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-10-01 13:48:15 +00:00
Shelley Vohr bd83a5cd7a child_process: build the default env block in one native pass
When spawn()/spawnSync() are called without options.env,
normalizeSpawnArguments() copied process.env with a spread and then
walked the copy to build the KEY=value array uv_spawn() takes.
Spreading the process.env proxy costs one enumerator callback plus a
query and a getter interceptor per variable, each doing a linear
getenv() scan and allocating; with a couple of hundred variables that
was the single largest JS-side cost of spawning a process.

Add KVStore::Pairs() (Enumerate() + Get() by default, one
uv_os_environ() pass for the real environment, skipping hidden
variables on Windows exactly like Enumerate() does), expose it as
process_wrap.getEnvPairs(), and use it for the default-environment
case. A user supplied options.env and the permission model case keep
the existing code. On Windows the same sort/first-wins-case-insensitive
filter is applied to the pairs. The variables copyProcessEnvToEnv()
propagates are part of the real environment by definition, and its
entries cannot contain null bytes, so those steps only remain on the
options.env path.

Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65325
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-30 13:30:42 +00:00
Filip Skokan 718f044f07 crypto: validate digest output encodings
Reject unknown Hash and Hmac digest encodings before finalizing the
operation instead of silently returning a Buffer. Preserve buffer
output aliases and existing encoding coercion.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66247
Fixes: https://github.com/nodejs/node/issues/45189
Refs: https://github.com/nodejs/node/pull/45990
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-30 06:51:22 +00:00
Filip Skokan 6b8001d219 crypto: validate update input encodings
Move unknown encoding validation into validateEncoding so Hash, Hmac,
Sign, and Verify reject invalid string input encodings alongside
Cipher and Decipher. Preserve ignored encodings for buffer inputs.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66247
Fixes: https://github.com/nodejs/node/issues/45189
Refs: https://github.com/nodejs/node/pull/45990
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-30 06:51:21 +00:00
Maruthan G 127f79a911 crypto: validate inputEncoding in Cipher/Decipher update
Cipher.update(string, badEncoding, ...) and Decipher.update with
the same shape silently produced incorrect output: the binding
skipped the unrecognized encoding and fell back to a default,
giving the user wrong ciphertext or plaintext with no signal.

Sub-cases 1 and 2 from issue #45189 (bad output encoding to
update/final) were addressed in PR #45990. This commit completes
the fix for sub-case 3 (bad input encoding) per panva's comment
deferring it to a follow-up PR for CITGM testing. When `data` is
a string and `inputEncoding` is non-null but does not normalize
to a known encoding, throw ERR_UNKNOWN_ENCODING. Buffer /
TypedArray / DataView data paths are unaffected (the binding
ignores `inputEncoding` for non-string data anyway).

Fixes: https://github.com/nodejs/node/issues/45189
Refs: https://github.com/nodejs/node/pull/45990
Signed-off-by: Maruthan G <maruthang4@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66247
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-30 06:51:19 +00:00
한국 d57738e5a5 crypto: fix raw key export error for wrong key type
Exporting a key in 'raw', 'raw-public' or 'raw-seed' format when the
key type does not match (e.g. an ECDSA private key as 'raw', or an
ML-KEM public key as 'raw-seed') fell through to the generic
NotSupportedError. The Web Crypto and modern-algos export key steps
require an InvalidAccessError in these cases.

Mirror exportKeySpki() and exportKeyPkcs8(): select the exporter per
algorithm first, then check the key type, and drop the type guards
around the call sites in exportKeySync(). Formats an algorithm does
not support (e.g. 'raw' for ML-DSA) still throw NotSupportedError.
This also fixes wrapKey(), which uses the same export path.

Assisted-by: a closed-source coding agent
Signed-off-by: koreahghg <koreahghg@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66217
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-29 23:56:19 +00:00
James Ross b42c0ccfa3 zlib: fix abort with decodeStrings: false
Passing decodeStrings: false to a zlib stream, or to an async
convenience method, let strings reach the native handle, which
aborts the process on its Buffer check. Force decodeStrings back to
true, as is already done for encoding and objectMode.

Signed-off-by: James Ross <james@jross.me>
PR-URL: https://github.com/nodejs/node/pull/66359
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
2026-09-29 21:48:17 +00:00
James Ross fa4af16414 zlib: pledge input size in async zstdCompress()
zstdCompress() writes its input and ends the frame in separate calls,
so zstd cannot infer the input size the way it does for
zstdCompressSync(), and sizes its tables for an unbounded stream.

Default pledgedSrcSize to the input's byte length. The output is now
identical to zstdCompressSync() and several times faster at higher
levels. An explicit pledgedSrcSize, or a string with a custom
defaultEncoding, keeps the current behavior.

Signed-off-by: James Ross <james@jross.me>
PR-URL: https://github.com/nodejs/node/pull/66358
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2026-09-29 21:23:49 +00:00
Filip Skokan e6b3f96cd0 worker: discard queued messages on termination
Close the outside port and remove its message forwarding listeners
synchronously. Closing the port alone is asynchronous and can leave
queued messages dispatching when terminate() runs inside a listener.

Allow the current event to finish while discarding subsequent messages,
including those drained when the backing thread exits.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66354
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-09-29 17:19:32 +00:00
Filip Skokan 74564d94df worker: serialize messages after exit
The outside port must serialize and transfer messages even when it has
no peer. Retain that port after the backing thread exits and create a
closed port when the entry script fetch fails. This preserves clone
errors and transfer side effects in both cases.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66354
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-09-29 17:19:29 +00:00
Filip Skokan f53f438a3b worker: preserve blob module URLs
Evaluate blob module sources under their original URL instead of
rewrapping them in a data URL. This preserves import.meta.url and module
identity while retaining the captured source after URL revocation.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66354
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-09-29 17:19:28 +00:00
Filip Skokan 5643755589 worker: convert importScripts arguments first
Web IDL converts every argument before entering the method algorithm.
Perform all USVString conversions before rejecting module workers or
parsing URLs, so later conversions can throw or revoke blob URLs first.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66354
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-09-29 17:19:26 +00:00
Filip Skokan ef8947aecf worker: fix postMessage overload resolution
Web IDL overload resolution treats functions as objects, accepts a null
iterator as missing, and retrieves the iterator method only once. Reuse
that method during sequence conversion in both postMessage entry points.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66354
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-09-29 17:19:25 +00:00
Lazizbek Ergashev 1f26576a3f http2: submit RST_STREAM before emitting 'aborted'
Signed-off-by: lazerg <lazerg2@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66314
Fixes: https://github.com/nodejs/node/issues/66306
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-09-29 10:27:53 +00:00
James M Snell 44ba289f55 http: add isValidHeaderName() and isValidHeaderValue()
Add non-throwing counterparts of http.validateHeaderName() and
http.validateHeaderValue() that return a boolean instead of throwing.

Rejecting an invalid header with the existing validators costs a few
microseconds, because an error object and its stack trace are created,
compared to ~20ns for the boolean check. Userland HTTP implementations
such as undici (fetch Headers, request options) therefore keep private
copies of the token and field-value tables from _http_common. These new
functions let them reuse the core implementation.

isValidHeaderValue() accepts an optional `httpValidation` option
('strict' or 'relaxed') that has the same meaning as the option of the
same name on http.createServer() and http.request().

Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66334
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
2026-09-29 04:38:26 +00:00
Samuel Attard 471fe813bb module: avoid allocating a cache key string for every require()
The relative resolve cache was keyed by a concatenated
${parent.path}\x00${request} string, allocating a new key for every
require() call including fully cached ones. Key the cache by the
parent directory first (a Map keyed by the already-retained
module.path string) and then by the request (a dictionary object,
whose property access internalizes dynamically-constructed
specifiers). Faster on every measured workload shape and slightly
smaller in memory, since the concatenated keys are no longer
retained.

Signed-off-by: Sam Attard <sattard@anthropic.com>
PR-URL: https://github.com/nodejs/node/pull/63884
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-28 23:30:13 +00:00
Robert Nagy 191a3b2db4 http2: emit close for aborted HEAD compat responses
The compat response defers 'finish' and 'close' for a HEAD request
until response.end(), because the stream of a headers-only response
closes as soon as the headers are sent. The same deferral also applied
to a HEAD stream that closed before any response was sent, for example
when the client cancelled it or the session was destroyed. Nothing was
left to call end(), so the response never emitted 'close' and the abort
could not be observed on it.

Defer only once the headers were sent, and otherwise close the response
as for any other method. The writable side of a HEAD stream is finished
from the start, so 'finish' is emitted only after the headers were
sent, and an aborted HEAD response does not report success.

Assisted-by: Opus 5.5
Signed-off-by: Robert Nagy <ronagy@icloud.com>
PR-URL: https://github.com/nodejs/node/pull/66310
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-09-28 10:40:58 +00:00
Matteo Collina cff7b12df1 stream: keep webstreams nil requests in fast mode
The shared "no pending request" records in the writable stream were
`__proto__: null` literals, which V8 creates in dictionary mode. They
sit in inFlightWriteRequest, closeRequest and pendingAbortRequest
whenever nothing is pending, and their promise field is checked several
times per write, so those loads did a hash lookup on every write and
every pipe. They are now built as plain literals and get their null
prototype afterwards, which keeps them in fast mode.

The readable controllers also initialized their state slot with an
empty object that setup replaced immediately. That throwaway allocation
is gone, matching the writable and transform controllers.

Add a writable-write benchmark: nothing in benchmark/webstreams drove
WritableStreamDefaultWriter.write() directly.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66230
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-28 07:51:16 +00:00
James M Snell 8f43e8884b buffer: add isLatin1
Implements a fast check to determine if a string is
a valid byte string (only chars <= 0xff).

Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66298
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
2026-09-28 04:22:37 +00:00
Marco 3641c36af1 watch: detect files replaced via unlink and create
Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63888
Fixes: https://github.com/nodejs/node/issues/51621
Refs: https://github.com/nodejs/node/issues/54774
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-27 09:36:07 +00:00
James M Snell 2ce7a73fec perf_hooks: fix truncation of monitorEventLoopDelay() resolution
`IntervalHistogram` stored the interval as `int32_t`, so a resolution
above 2^31 - 1 ms wrapped: `resolution: 2 ** 32 + 1` sampled every
millisecond.

Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: OpenCode
PR-URL: https://github.com/nodejs/node/pull/66115
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-27 08:10:15 +00:00
Lazizbek Ergashev cd908df27f worker: add Symbol.toStringTag to BroadcastChannel
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65532
Fixes: https://github.com/nodejs/node/issues/65527
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-27 00:37:26 +02:00
Lazizbek Ergashev b456adbcd6 worker: add Symbol.toStringTag to MessageChannel and MessagePort
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65532
Fixes: https://github.com/nodejs/node/issues/65527
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-27 00:37:25 +02:00
Matteo Collina 7ff62671a5 stream: keep consumer state in fast mode
Create null-prototype share and broadcast consumer state with fast
   properties instead of V8 dictionary properties.

Assisted-by: Pi
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66266
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-26 21:43:46 +00:00
James M Snell f378cfcfbf src,lib: add --allow-env permission
Necessarily semver-major.

When `--permission` is on, every env var not matched by
`--allow-env` is removed at startup. It takes names,
prefix patterns (`PREFIX_*`), or `*`, repeatable or
comma-sep'd.

There are a range of env vars that Node.js itself uses,
and a default range that are generally known to be safe
in common usage. These are never scrubbed. These include
things like `NODE_OPTIONS`, `NODE_EXTRA_CA_CERTS`, `PATH`,
`HOME`, etc. `NODE_ENV` is not in the defaults and must
be allowed explicitly.

Proxy vars (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) are
also not in the defaults since they can carry credentials.
When `--use-env-proxy` or `NODE_USE_ENV_PROXY` is set and
any of them were removed, a single warning naming them is
emitted.

Env vars can be dropped at runtime after reading using
`permission.drop()`. This is a stronger protection than
using `process.env.FOO = undefined` because it will
scrub the env var also from the environment block.

On Linux, the removed entries are overwritten in the
initial environment block. fs reads of any other
process's /proc/<pid>/environ, ancestors included, are
denied regardless of `--allow-fs-read`. A process's own
is readable only with `--allow-env=*`. Symlinks are
resolved before the check so paths like
/dev/fd/../../<ppid>/environ are caught. The check only
canonicalizes paths that statfs() reports are on procfs.

On Windows, removal also clears the C runtime's copy
of the environ using _wputenv_s.

Reading a removed name returns undefined, warns once per
name, and publishes to a diagnostics channel.

Env file keys are allowed. If the user had reason to pass
in an env file the assumption is they meant to allow them.

File-source config (node.config.json and NODE_OPTIONS
from a .env file) can only narrow the allow list.

Embedders must call ScrubProcessEnvironment() themselves
on startup. This is left up to the embedder to determine
the exact timing but needs to be called before startup
actually happens.

Child processes are started with `--allow-env=*`. Those
either receive the explicit env they were started with
or only the env they inherit from the parent. Since the
parent process is scrubbed, and the child cannot read
any other process's /proc/<pid>/environ, it should never
see more than the parent can.

Main part of the impl was done by hand. Docs, tests,
verification pass, and cleanup nits were automated.

Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/66132
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-09-26 21:18:43 +00:00
Lazizbek Ergashev 261c8a196c events: fix addAbortListener for aborted signals
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65640
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
2026-09-26 20:55:09 +00:00
Yagiz NizipliandYagiz Nizipli 6a6e09e834 querystring: speed up default parse and unescape
Skip the %XX walk in unescapeBuffer when the input has no '%'.
Add a dedicated '&'/'=' scanner for the default parse path so
it does not build separator code arrays or run the multi-char
state machine.

Official benchmark/querystring/querystring-parse.js:
encodemany is about 38% faster, manyblankpairs about 17%,
encodelast about 10%, noencode about 8%.
Official querystring-unescapebuffer.js with no escapes is
about 36% faster.

Assisted-by: a closed-source coding agent
Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Co-authored-by: Yagiz Nizipli <anonrig@users.noreply.github.com>
PR-URL: https://github.com/nodejs/node/pull/66175
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-09-26 20:34:53 +00:00
Christian Aurich Zanettini Martins 1e17275dea fs: fix crash on negative zero file descriptor
`isInt32()` accepts -0 because `-0 === (-0 | 0)`, but V8 does not
represent -0 as an Int32 value, so `Value::IsInt32()` rejects it. The
utf8 fast paths of `readFileSync()` and `writeFileSync()` hand the value
straight to the binding, which then took it for a path and aborted on
the null check.

Coerce -0 to 0 before the call, matching `getValidatedFd()` and the rest
of fs, where -0 is a valid way to name file descriptor 0.

Signed-off-by: Christian Aurich <christian.aurichzm@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65888
Fixes: https://github.com/nodejs/node/issues/65886
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
2026-09-26 19:52:53 +00:00
Dayun d9208ccdcc worker: remove messageerror listeners on exit
Signed-off-by: Dayun <dlekdbs6530@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66075
Fixes: https://github.com/nodejs/node/issues/65782
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-26 19:42:29 +00:00
Dayun 31e841f056 stream: fix pipeline function tail deadlock
Signed-off-by: Dayun <dlekdbs6530@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65559
Fixes: https://github.com/nodejs/node/issues/40685
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-26 19:32:45 +00:00
Hubert Walczak db1e36b8dd worker: strip types in Web Worker module entries
Strip TypeScript from file-backed module worker entries before
evaluating the fetched source.

Add regression coverage and document the supported entry types.

Assisted-by: Codex
Signed-off-by: Hubert Walczak <hubertwalczak8@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66085
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
2026-09-26 18:28:17 +00:00
Tim Perry af13502159 benchmark: fix shadowing that broke h=20 on incoming_headers benchmark
Previously the inner 'headers' variable shadowed the outer, meaning that
headers=20 sends the same 7 headers as headers=0.

Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66257
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-09-26 18:27:41 +00:00
Efe Karasakal c0681e5179 http: normalize CONNECT request paths
Signed-off-by: Efe Karasakal <hi@efe.dev>
PR-URL: https://github.com/nodejs/node/pull/64876
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-09-26 14:02:54 +00:00
Yagiz Nizipli 4889fb0a43 stream: skip write() checks in flowing pipe
pipe() installs one 'data' listener that calls dest.write() for
every chunk. That repeats encoding, mode, and end checks that stay
the same for a synchronous buffer write.

When that listener is still the only one, hand the Buffer to the
same synchronous write path without those checks. A second
listener, a non-buffer chunk, or a busy writable still goes through
emit('data').

On top of the flowing-read fast path, benchmark/streams/pipe.js is
about 31% faster (20 runs). Object-mode pipe and readable-readall
stay within noise.

Assisted-by: a closed-source coding agent
Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
PR-URL: https://github.com/nodejs/node/pull/66182
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Zeyu "Alex" Yang <himself65@outlook.com>
2026-09-26 06:47:49 +00:00
Yagiz Nizipli 236b53ff62 stream: speed up flowing pipe of buffers
flow() pulls one already-buffered chunk and calls _read() for the
next one on every iteration. That goes through the general read()
path, which updates a holey buffer array and then pulls the chunk
back out.

While a synchronous byte-mode flow is in progress, keep that
prefetched chunk on the readable state and emit it directly.
_read() of the next chunk still runs before 'data', and a nested
read() moves the chunk back onto the buffer.

benchmark/streams/pipe.js is about 77% faster (15 runs).
pipe-object-mode, readable-readall, and readable-bigread stay
within noise.

Assisted-by: a closed-source coding agent
Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
PR-URL: https://github.com/nodejs/node/pull/66182
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Zeyu "Alex" Yang <himself65@outlook.com>
2026-09-26 06:47:48 +00:00
Guilherme Araújo f2b698f1cf sqlite: rename DatabaseSync and StatementSync
Rename the DatabaseSync and StatementSync classes to Database and
Statement, and the internal DatabaseSyncLimits helper to
DatabaseLimits. The old names are kept as aliases of the new classes
and are Documentation-only deprecated (DEP0210, DEP0211).

Assisted-by: Claude Code
Signed-off-by: Guilherme Araújo <arauujogui@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65988
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2026-09-26 00:03:45 +00:00
Matteo Collina 9c06dab7d0 http: pass maxHeaderPairs to parser.initialize()
The parser read the `maxHeaderPairs` property from its JS object in
C++ once per header section to enforce the header count limit. That
lookup is a runtime property load for every parsed request, and costs
up to 7% on the parser benchmark for requests with few headers.

Pass the limit to `initialize()` instead and keep it in a field. The
property is still set, as the JS side uses it to trim the header list.

Refs: https://github.com/nodejs/node/pull/64988
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66250
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
2026-09-25 21:29:33 +00:00
Yagiz Nizipli 4bd56b3590 http: avoid toLowerCase on the server hot path
After #65802, Host/Expect/body checks still allocate
toLowerCase() copies and Expect/HTTP/1.0 TE still
read req.headers. Compare names without allocating,
read those values from rawHeaders, intern parser
header names, and skip Title-Case toLowerCase on
common outgoing fields.

Refs: https://github.com/nodejs/node/pull/65802
Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: a closed-source coding agent
PR-URL: https://github.com/nodejs/node/pull/66120
Refs: https://github.com/nodejs/node/pull/65332
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-25 20:47:42 +00:00
Christian Aurich Zanettini Martins cc610f1cfb fs: validate falsy openAsBlob type option
openAsBlob() and openAsBlobSync() read the MIME type as
options.type || '' before validating it, causing falsy non-string
values to be replaced with the default before reaching validateString().
As a result, { type: 0 }, { type: false }, { type: null }, and
{ type: NaN } are accepted as an empty type, while { type: 1 }
throws ERR_INVALID_ARG_TYPE.

Default the option only when it is undefined so all other values are
validated against the documented string type.

Signed-off-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66125
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-25 19:44:48 +00:00
agape1225 118f2a1d78 stream: support ArrayBufferView in Utf8Stream write() buffer mode
Utf8Stream#write() in 'buffer' content mode only accepted Buffer
instances, even though the underlying implementation only needs
byte-addressable data. This accepts any ArrayBufferView (TypedArray,
DataView) and reinterprets it as a Buffer over the same bytes
(without copying), so callers no longer need to wrap other typed
arrays in Buffer.from() themselves.

Views are normalized to a Buffer at the single entry point
(#writeBuffer), using byteOffset/byteLength rather than the view's
element-count length, so that internal length bookkeeping used by
mergeBuf()/Buffer.concat() and the write-release logic keeps
operating on real byte counts. This mirrors the existing pattern in
zlibBuffer() (lib/zlib.js).

Signed-off-by: agape1225 <49804691+agape1225@users.noreply.github.com>
PR-URL: https://github.com/nodejs/node/pull/65301
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-09-25 21:32:36 +02:00
XadillaX 5ebf690dcf http: preserve socket errors as response error causes
Keep the original socket error as the cause of ECONNRESET errors emitted
when an HTTP response closes before completion. Preserve the existing
aborted message, error code, and event order. Leave cause absent when
there is no underlying error.

Allow ConnResetException to accept Error options, document the behavior,
and cover TLS record errors, TCP resets, explicit destruction, and
premature closure without a socket error.

This follows investigation of #66001 and addresses lost error context.
The original TLS decryption failure remains unresolved.

Refs: https://github.com/nodejs/node/issues/66001
Signed-off-by: XadillaX <i@2333.moe>
PR-URL: https://github.com/nodejs/node/pull/66061
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-09-25 21:31:04 +02:00
James M Snell 990aefdf56 lib: fix stream loading bug in node:bench
Not all of the stream APIs are correctly loaded until
the `node:stream` module is loaded.

Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/66114
Fixes: https://github.com/nodejs/node/issues/41641
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-09-25 18:49:36 +00:00