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>
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>
backup() only checked that the source argument was a BaseObject before
casting it to Database, so passing a Statement or Session caused a
type confusion. Check against the Database constructor template
instead.
Signed-off-by: Guilherme Araújo <arauujogui@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66797
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
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>
`Channel` reads its subscriber count through a raw `BindingData*` that
was never cleared, so any native holder that outlives environment
cleanup reads a destroyed object. The null check in `HasSubscribers()`
could not fire, because the pointer was only ever assigned in the
constructor.
`node:sqlite` holds a strong `BaseObjectPtr<Channel>` for the lifetime
of a `Database`, which made this reachable from ordinary
JavaScript. A statement left mid-step at exit is finalized by the
destructor chain after `Environment::RunCleanup()` has destroyed the
binding, and `sqlite3_finalize()` invokes the profile callback for such
a statement. The result was a segfault at normal process exit; inside a
worker it took down the whole process.
Clear `binding_data_` on every `Channel` the binding owns whenever it
gives up that ownership, both in the destructor and in
`PrepareForSerialization()`, so that the existing null check in
`HasSubscribers()` does its job. The second check in `Publish()` is now
unreachable and is dropped. This protects any holder that is itself a
`BaseObject`, and so is destroyed later in the same cleanup. A holder
that is not a `BaseObject` still needs a cleanup hook or a weak
reference, because `Realm::~Realm()` checks that no `BaseObject`s
remain.
On the `node:sqlite` side, switch `Database::trace_channel_` to a
`BaseObjectWeakPtr`, so that it follows the same convention `permission`
documents, where `BindingData` is the sole owner of channels.
`TraceCallback` already null-checks, so this needs no other change
there.
Also check `AreTraceEventsSuppressed()` before the channel in
`TraceCallback()`, so that a suppressed callback does not dereference it
at all. `Statement::Finalize()` already suppresses trace events, so
the reported path was meant to be a no-op; only the order of the `||`
operands took it through the channel first.
Fixes: https://github.com/nodejs/node/issues/65858
Assisted-by: Claude Opus 5
Signed-off-by: Trevor Burnham <trevorburnham@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65860
Reviewed-By: Bryan English <bryan@bryanenglish.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Closing a virtual table cursor invoked the iterator's return() even
after next() had already reported done: true, deviating from for...of
semantics where return() only runs on abrupt termination. An empty
custom iterable with a throwing return() made an otherwise successful
query fail.
Only close the iterator when the scan stopped early, as with LIMIT, a
break, or a cursor re-filter; a normally finished iterator already ran
its cleanup.
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/66519
Fixes: https://github.com/nodejs/node/issues/66518
Reviewed-By: Guilherme Araújo <arauujogui@gmail.com>
Run supported DH, ECDH, legacy TLS, TLS 1.2 PSK, cipher metadata,
raw key, and X.509 date cases with BoringSSL. Assert its DH flags,
curve format errors, and name-constraint behavior. Narrow key/cert
array exclusions to the failing multi-identity cases.
Use modp5 for the DH group setter checks and remove the unused legacy
protocol fallback helper.
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>
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>
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>
When a peer sends GOAWAY(NO_ERROR), the session starts a graceful close
on its own, which disarmed the detection of nghttp2 internally
terminating the session after a protocol error. Instead, also treat it
as an internal termination when nghttp2 no longer wants to read or
write while we still have open streams.
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66641
Reviewed-By: Tim Perry <pimterry@gmail.com>
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>
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>
The readBigInts, returnArrays, allowBareNamedParameters and
allowUnknownNamedParameters options were read with
`if (Get().ToLocal())`, so a throwing getter left an exception pending
while the constructor carried on. Option parsing continued, the
database was opened, and the exception was lost, leaving a database
file on disk for a constructor call that should have failed.
Return as soon as reading any of these options fails, matching how
every other option is handled.
Signed-off-by: Guilherme Araújo <arauujogui@gmail.com>
Assisted-by: Claude
PR-URL: https://github.com/nodejs/node/pull/66748
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
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>
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>
SSL_read() returns at most one TLS record, and ClearOut() emitted a
separate read for each one. Peers that use small records, such as
nginx with its default 4 KiB ssl_buffer_size or servers doing dynamic
record sizing, made every record pay for its own buffer allocation
and call into JavaScript.
While the next buffered record is application data, keep reading into
the same 16 KiB buffer before emitting it, so reads never get larger
than one full record already makes them. Batching stops before any
other record type, so that e.g. a TLS 1.2 renegotiation is still
processed after the data in front of it has been emitted. It also
stops before records short enough to be empty, because SSL_read()
skips empty records and carries on with the next one. If SSL_read()
fails in the middle of a batch, the error is captured first and
reported after the data.
test-tls-max-send-fragment relied on 'data' chunks matching records,
so it now checks the record sizes on the wire.
Signed-off-by: Robert Nagy <ronagy@icloud.com>
Assisted-by: claude:opus-5.5
PR-URL: https://github.com/nodejs/node/pull/66698
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Check X.509 ASN.1, BIO, time, OID, and DER conversion results.
Preserve invalid-time diagnostics, reject incomplete BIO writes, format
RSA exponents atomically, and avoid truncating long object identifiers.
Preserve valid siblings in legacy name objects by omitting individual
non-text AttributeValues. Continue treating structural failures and
failed conversion of supported string types as conversion failures.
Reject empty or malformed SAN and AIA extensions, and prevent TLS
hostname checks from falling back to commonName after a malformed SAN.
Guard missing public keys and non-NIST curve names. Scope fallible
backend probes without consuming callback errors, parse checkIP()
inputs to exact address bytes, and preserve unrelated backend errors.
Assisted-by: Codex
Co-authored-by: Matteo Collina <hello@matteocollina.com>
Signed-off-by: Matteo Collina <hello@matteocollina.com>
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Refs: https://hackerone.com/reports/3910015
Refs: https://hackerone.com/reports/3824331
Refs: https://hackerone.com/reports/3944830
Refs: https://hackerone.com/reports/3944847
PR-URL: https://github.com/nodejs-private/node-private/pull/966
Reviewed-By: James M Snell <jasnell@gmail.com>
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
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
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
The test was skipped unless Node.js was built with QUIC, but the JSON
schema is generated from a build with the default configuration
options, where QUIC is disabled. As a result the test never ran in CI
and the schema was no longer checked.
Skip the test instead when QUIC, DTLS or the V8 sandbox are enabled,
or when FFI is disabled, since each of these changes the set of
available options. Also remove the check for the `node_quic` variable,
which no longer exists.
Compare the schemas with assert.deepStrictEqual() so that a failure
shows which options differ instead of two long strings.
Assisted-by: claude:opus-5.5
Signed-off-by: Marco Ippolito <marcoippolito54@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66827
Reviewed-By: Pietro Marchini <pietro.marchini94@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Node.js embeds the Mozilla root store but has no equivalent of the
browsers' CRLSet/OneCRL and no default online revocation checking, so a
certificate chain through a compromised intermediate still verifies as
long as it reaches a trusted root. Removing the affected roots would
over-block, since other legitimate intermediates chain to them.
Add a small compiled-in blocklist of SubjectPublicKeyInfo SHA-256 hashes
and check every verified chain against it from a single
SSL_CTX_set_cert_verify_callback hook. A hit is reported as
X509_V_ERR_CERT_REVOKED through the normal verification path, so it
honours rejectUnauthorized and surfaces as authorizationError on both
client and server sockets. The hook is installed for every SSL_CTX
Node.js creates: SecureContext, QUIC and DTLS. The OpenSSL 4.1 CN name
constraint handling previously registered from crypto_tls.cc moves into
the same hook, since OpenSSL allows only one.
The initial entries are the eight eMudhra/emSign intermediates whose
private keys were reported compromised in October 2026. The same list is
shipped by Go (CVE-2026-111943) and Electron.
Sessions resumed from before this change are not re-verified, as is
standard for TLS resumption; the exposure ends with the session timeout.
Test-only hooks on the crypto binding, reachable with
--expose-internals, allow the test to block a fixture key and exercise
the full handshake.
Refs: https://github.com/electron/electron/pull/55126
Refs: https://github.com/golang/go/issues/82345
Assisted-by: Claude, Codex
Signed-off-by: Ulises Gascon <ulisesgascongonzalez@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66871
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Bryan English <bryan@bryanenglish.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
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>