Skip to content

webcrypto: deriveBits and deriveKey crash k6 on a missing base key or a negative length #6523

Description

@BlairCurrey

Brief summary

A few invalid arguments to crypto.subtle.deriveBits and crypto.subtle.deriveKey make k6 panic in a background goroutine. The whole process exits, instead of the promise rejecting with an error the script can catch.

  • A missing base key (undefined) crashes deriveBits (ECDH and PBKDF2) and deriveKey (PBKDF2).
  • A negative length crashes ECDH deriveBits.

k6 version

v2.3.0 (latest release). The affected code is unchanged on master as of 2026-09-30 (2a83804).

OS

macOS (darwin/arm64). Not OS-specific.

Docker version and image (if applicable)

No response

Steps to reproduce the problem

Each of these scripts crashes k6:

// missing base key (also crashes with the PBKDF2 algorithm)
export default async function () {
  const kp = await crypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256" }, true, ["deriveBits"]);
  await crypto.subtle.deriveBits({ name: "ECDH", public: kp.publicKey }, undefined, 256);
}
// missing base key in deriveKey
export default async function () {
  const params = { name: "PBKDF2", hash: "SHA-256", salt: new Uint8Array(16), iterations: 1000 };
  await crypto.subtle.deriveKey(params, undefined, { name: "AES-GCM", length: 256 }, true, ["encrypt"]);
}
// negative length
export default async function () {
  const kp = await crypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256" }, true, ["deriveBits"]);
  await crypto.subtle.deriveBits({ name: "ECDH", public: kp.publicKey }, kp.privateKey, -8);
}

Wrapping the calls in try/catch doesn't help, as the panic happens in a goroutine.

Expected behaviour

The promise rejects, and the script can handle the error. A missing base key would be a TypeError, as baseKey must be a CryptoKey.

Actual behaviour

k6 exits with a Go panic:

panic: runtime error: invalid memory address or nil pointer dereference
panic: runtime error: slice bounds out of range [:-1]

For reference, PBKDF2 deriveBits with a negative length doesn't crash, but rejects with an error whose name and message are both undefined.

Cause and possible fix

  • rt.ExportTo(baseKey, &privateKey) leaves privateKey nil for undefined, and nothing checks it before use (subtle_crypto.go#L757 for deriveBits, #L611 for deriveKey). A nil check there, rejecting with a TypeError, would cover all algorithms.
  • A negative length passes the length == 0 and length%8 != 0 checks (#L773-L781), and ECDH then slices with it (elliptic_curve.go#L573). Rejecting length < 0 in DeriveBits would fix it.

Related to #4258, which tracks panics in the WebCrypto module more generally.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions