Commit f930e3ad449 for nodejs

commit f930e3ad44976b756efabbe4dcb5e2df6ee1d4b6
Author: Filip Skokan <panva.ip@gmail.com>
Date:   Tue Sep 22 22:25:22 2026 +0200

    crypto: copy derived bits without species

    Use the byte-copy helper for truncated ECDH results so ArrayBuffer
    species cannot replace or resize the returned key material.

    Signed-off-by: Filip Skokan <panva.ip@gmail.com>
    Assisted-by: Codex
    PR-URL: https://github.com/nodejs/node/pull/66237
    Reviewed-By: James M Snell <jasnell@gmail.com>
    Reviewed-By: Aviv Keller <me@aviv.sh>

diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js
index 63a9451b3cc..46659419c8d 100644
--- a/lib/internal/crypto/diffiehellman.js
+++ b/lib/internal/crypto/diffiehellman.js
@@ -2,7 +2,6 @@

 const {
   ArrayBufferPrototypeGetByteLength,
-  ArrayBufferPrototypeSlice,
   FunctionPrototypeCall,
   ObjectDefineProperty,
   TypedArrayPrototypeGetBuffer,
@@ -381,11 +380,8 @@ function ecdhDeriveBits(algorithm, baseKey, length) {
     if (byteLength < sliceLength)
       throw lazyDOMException('derived bit length is too small', 'OperationError');

-    if (length % 8 === 0) {
-      if (byteLength === sliceLength)
-        return bits;
-      return ArrayBufferPrototypeSlice(bits, 0, sliceLength);
-    }
+    if (length % 8 === 0 && byteLength === sliceLength)
+      return bits;

     return TypedArrayPrototypeGetBuffer(truncateToBitLength(length, bits));
   });
diff --git a/test/parallel/test-webcrypto-derived-bits-species.js b/test/parallel/test-webcrypto-derived-bits-species.js
new file mode 100644
index 00000000000..491dc0df877
--- /dev/null
+++ b/test/parallel/test-webcrypto-derived-bits-species.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+  common.skip('missing crypto');
+
+const assert = require('assert');
+const { subtle } = globalThis.crypto;
+
+(async () => {
+  const keys = await subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, false, ['deriveBits']);
+  const algorithm = { name: 'ECDH', public: keys.publicKey };
+  const expected = await subtle.deriveBits(algorithm, keys.privateKey, 128);
+  const species = Object.getOwnPropertyDescriptor(ArrayBuffer, Symbol.species);
+  Object.defineProperty(ArrayBuffer, Symbol.species, {
+    configurable: true,
+    get: common.mustNotCall(),
+  });
+  try {
+    const actual = await subtle.deriveBits(algorithm, keys.privateKey, 128);
+    assert.deepStrictEqual(actual, expected);
+    assert.strictEqual(Object.getPrototypeOf(actual), ArrayBuffer.prototype);
+  } finally {
+    Object.defineProperty(ArrayBuffer, Symbol.species, species);
+  }
+})().then(common.mustCall());