{"record":{"id":"c6f4276da57ed63c","repo":"denoland/deno","slug":"zero-length-key-is-not-supported","errorCode":null,"errorMessage":"Zero-length key is not supported","messagePattern":"Zero-length key is not supported","errorType":"exception","errorClass":"DOMException","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/crypto/keys.ts","lineNumber":751,"sourceCode":"      type: \"NodeCryptoKeyObject\",\n      keyType: \"secret\",\n      keyData: new Uint8Array(op_node_export_secret_key(this[kHandle])),\n    };\n  }\n\n  toCryptoKey(\n    algorithm: string | object,\n    extractable: boolean,\n    usages: string[],\n  ): CryptoKey {\n    const algName = typeof algorithm === \"string\"\n      ? algorithm\n      : (algorithm as { name: string }).name;\n\n    const rawData = new Uint8Array(op_node_export_secret_key(this[kHandle]));\n\n    if (TypedArrayPrototypeGetByteLength(rawData) === 0) {\n      throw new DOMException(\n        \"Zero-length key is not supported\",\n        \"DataError\",\n      );\n    }\n\n    if (algName === \"PBKDF2\") {\n      if (extractable) {\n        throw new DOMException(\n          \"PBKDF2 keys are not extractable\",\n          \"SyntaxError\",\n        );\n      }\n      if (\n        usages.length > 0 &&\n        ArrayPrototypeSome(\n          usages,\n          (u: string) =>\n            !ArrayPrototypeIncludes([\"deriveKey\", \"deriveBits\"], u),","sourceCodeStart":733,"sourceCodeEnd":769,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/crypto/keys.ts#L733-L769","documentation":"SecretKeyObject.toCryptoKey exports the secret key's raw bytes and refuses zero-length material with a DataError DOMException, mirroring the WebCrypto rule that an imported secret must carry at least one byte. This guard runs before algorithm-specific checks (PBKDF2/HKDF/HMAC usage validation) and before importCryptoKeySync.","triggerScenarios":"createSecretKey(Buffer.alloc(0)).toCryptoKey(alg, extractable, usages); a secret built from an empty string/env value (Buffer.from('') has length 0) then converted to a CryptoKey via KeyObject.toCryptoKey (used by webcrypto interop).","commonSituations":"An env var that exists but is empty (API_SECRET='') decoded to an empty buffer; slicing a buffer with wrong offsets yielding length 0; a default empty secret in staging config that nobody exercised; test fixtures with empty key material.","solutions":["Validate byte length > 0 when creating the secret: if (!buf.length) throw ... at startup","Treat empty secrets as configuration errors and refuse to boot","Watch for Buffer.slice/subarray mistakes that produce zero-length views","For AES keys also meet the algorithm minimum (16/24/32 bytes) — later checks enforce that separately"],"exampleFix":"// before: empty env value becomes a zero-length key\nconst secret = crypto.createSecretKey(Buffer.from(process.env.API_SECRET ?? ''));\nconst ck = secret.toCryptoKey('AES-GCM', false, ['encrypt']); // DataError\n\n// after: fail fast on empty material\nconst raw = Buffer.from(process.env.API_SECRET ?? '', 'base64');\nif (raw.length === 0) throw new Error('API_SECRET is empty');\nconst ck = crypto.createSecretKey(raw).toCryptoKey('AES-GCM', false, ['encrypt']);","handlingStrategy":"validation","validationCode":"function toCryptoKey(secretKeyObject, alg, extractable, usages) {\n  const raw = Buffer.from(secretKeyObject.export());\n  if (raw.length === 0) {\n    throw new Error('refusing to convert a zero-length secret key');\n  }\n  return secretKeyObject.toCryptoKey(alg, extractable, usages);\n}","typeGuard":"function isNonEmptySecret(key: crypto.KeyObject): boolean {\n  return key.type === 'secret' &&\n    Buffer.from(key.export()).length > 0;\n}","tryCatchPattern":"try {\n  return secretKey.toCryptoKey(alg, extractable, usages);\n} catch (err) {\n  if (err instanceof DOMException && err.name === 'DataError' &&\n      /Zero-length key/.test(err.message)) {\n    throw new Error('Secret material is empty — check env/config source');\n  }\n  throw err;\n}","preventionTips":["Validate secret length > 0 (and >= algorithm minimum) at configuration load time","Treat empty-but-present env vars as missing","Test key plumbing with the same shapes production uses (base64 env values, file reads)"],"tags":["crypto","webcrypto","secret-key","cryptokey","node-compat"],"backgroundTag":"empty-secret-key","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}