]> git.kaiwu.me - njs.git/commitdiff
WebCrypto: fix crypto.getRandomValues() with non-buffer arguments
authorDmitry Volyntsev <xeioex@nginx.com>
Fri, 30 Oct 2026 02:10:44 +0000 (19:10 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Mon, 2 Nov 2026 14:42:35 +0000 (06:42 -0800)
Previously, crypto.getRandomValues() obtained the destination bytes
with njs_vm_value_to_bytes(), which also accepts strings and does not
make a private copy of shared data.  As a result:

  - for a string argument the random bytes were written into the
    string data, which may be shared with other strings, including
    literals in the script;
  - for r.requestBuffer in nginx the request body seen by subsequent
    reads was modified.

Now, only typed arrays and DataView objects are accepted, and the
buffer is made writable before the write.

The issue was introduced in 7b2b7612 (0.7.0).

external/njs_webcrypto_module.c
src/test/njs_unit_test.c

index c93a2298d4c56dc45afa2c0642b7ee39d426d6e5..c14d9288561e04b51dfa8994d86ccef6591d0d16 100644 (file)
@@ -5555,7 +5555,7 @@ njs_ext_get_random_values(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     buffer = njs_arg(args, nargs, 1);
 
-    ret = njs_vm_value_to_bytes(vm, &fill, buffer);
+    ret = njs_value_buffer_get(vm, buffer, &fill);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
index c4671b6be929a1648ddbe9918712ccc108dafcd3..f133be0b2694ba3359ff649617e1e3351dccf08e 100644 (file)
@@ -22049,6 +22049,19 @@ static njs_unit_test_t  njs_externals_test[] =
               "[b[0], $r.buffer[0]]"),
       njs_str("64,208") },
 
+#if (NJS_HAVE_OPENSSL)
+    { njs_str("var b = $r.buffer; crypto.getRandomValues(b);"
+              "[b.length, $r.buffer[0]]"),
+      njs_str("22,208") },
+
+    { njs_str("var v = new DataView(new ArrayBuffer(4));"
+              "crypto.getRandomValues(v) === v"),
+      njs_str("true") },
+
+    { njs_str("var s = 'abc' + 'defgh'; crypto.getRandomValues(s)"),
+      njs_str("TypeError: first argument must be a Buffer or DataView") },
+#endif
+
     { njs_str("$r.buffer instanceof Buffer"),
       njs_str("true") },