You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
doc: crypto.randomBytes, randomInt, randomUUID and getRandomValues continue from the saved state after a snapshot or checkpoint restore #66880
We measure how userspace random generators behave when a process or a machine is duplicated.
For Node 24.18.0 linked against the system OpenSSL 3.5.9 (Fedora 44, Linux 7.2.11) the picture is
this; the harness and every log are available.
One guest or process saved and restored twice from the same image, the two continuations'
outputs compared block by block at equal sequence numbers: Math.random, crypto.randomBytes, crypto.randomInt and crypto.getRandomValues are 32 of 32 blocks identical under QEMU with and
without a vmgenid device and under Firecracker with VMGenID and VMClock attached, and 14 of 14
under CRIU; a read of /dev/urandom beside them is distinct from the first block wherever the
guest kernel's vmgenid driver is present. The three crypto calls repeat because OpenSSL's
DRBG does; Math.random repeats because V8's generator is seeded once per isolate. We asked
the OpenSSL project where it places the case; its answer (2026-10-20) is that reseeding after a
restore "is currently a non-goal", not yet documented, that a documentation pull request will
be accepted and backported, and that a check-and-reseed on the VMClock generation counter would
be considered as a new feature for a future release.
What we would like to know is whether the crypto documentation should say that these calls
inherit OpenSSL's behaviour across a snapshot or checkpoint restore, so that applications
resumed from one image (SnapStart-style platforms, CRIU) know to arrange a reseed, and whether
Node would want to call RAND_poll itself on a restore signal (its own startup snapshot
feature, --build-snapshot, resumes an isolate from an image in the same way, and crypto.randomUUID serves identifiers from a cache of 128 filled in one draw,
lib/internal/crypto/random.js).
The repeated blocks are the generators' own output; we have not looked at anything downstream.
Concretely, a sentence in the crypto documentation of the kind "these functions draw from OpenSSL's DRBG inside the process; after a snapshot or checkpoint restore the DRBG continues from the saved state until its next scheduled reseed, so an application resumed from a saved image should reseed after its own restore signal" would tell such applications what to do, and crypto.randomUUID could note its cache of 128 identifiers (lib/internal/crypto/random.js, disableEntropyCache turns it off). We can send a documentation pull request if that is welcome. The harness, the logs and the OpenSSL exchange are available on request.
// Clear cached random data after user serialization callbacks.
addAfterUserSerializeCallback(resetRandomCaches);
OpenSSL is initialized per process at runtime (InitCryptoOnce) and isn't part of the V8 startup snapshot, so a process started from a snapshot gets a freshly seeded DRBG:
fprintf(stderr, "Unable to load legacy provider.\n");
}
}
OPENSSL_init_ssl(0, settings);
InstallFipsIndicatorCallback();
ncrypto::ConfigurePqcEncoding();
So the remaining thing seems to be external checkpoint/restore (CRIU, VM snapshots), where the whole process memory is duplicated and there is no way for Node to notice.
One problem with documenting "reseed after restore" is that Node doesn't currently expose any way to reseed OpenSSL from JS. The closest mitigation is randomUUID({ disableEntropyCache: true }), which only covers the UUID cache.
Would a doc note that just describes the behavior (no reseed advice) be welcome, or would maintainers rather consider an API for this first? @KurathSec, you said about sending docs PR. Will you still send? If not, I'm ready to work on it.
Thanks. The question here is still for the maintainers: whether the docs should describe this at all. We offered a PR if that is welcome, and no maintainer has answered yet, so I would wait for that before anyone writes it.
You are right that OpenSSL's DRBG is not part of the startup snapshot and that Node has no reseed API, so the sentence proposed above would need to change. The cache reset is in 22.23.4, 24.22.1 and 26.12.1; the measurements above are from 24.18.0.
Activity
BilalWalker commentedon Nov 7, 2026
I looked into it then traced it with help from a coding assistant and checked the code myself.
For Node's own
--build-snapshot, I think this is already handled:randomIntcache and therandomUUIDbatch of 128) are zeroed when the snapshot is serialized:node/lib/internal/crypto/random.js
Lines 400 to 415 in d1a1621
InitCryptoOnce) and isn't part of the V8 startup snapshot, so a process started from a snapshot gets a freshly seeded DRBG:node/src/crypto/crypto_util.cc
Lines 478 to 516 in d1a1621
So the remaining thing seems to be external checkpoint/restore (CRIU, VM snapshots), where the whole process memory is duplicated and there is no way for Node to notice.
One problem with documenting "reseed after restore" is that Node doesn't currently expose any way to reseed OpenSSL from JS. The closest mitigation is
randomUUID({ disableEntropyCache: true }), which only covers the UUID cache.Would a doc note that just describes the behavior (no reseed advice) be welcome, or would maintainers rather consider an API for this first? @KurathSec, you said about sending docs PR. Will you still send? If not, I'm ready to work on it.
KurathSec commentedon Nov 7, 2026
Thanks. The question here is still for the maintainers: whether the docs should describe this at all. We offered a PR if that is welcome, and no maintainer has answered yet, so I would wait for that before anyone writes it.
You are right that OpenSSL's DRBG is not part of the startup snapshot and that Node has no reseed API, so the sentence proposed above would need to change. The cache reset is in 22.23.4, 24.22.1 and 26.12.1; the measurements above are from 24.18.0.