cloudflare / cloudflare/workerd

🐛 Bug Report Runtime APIs node:crypto: Hmac.prototype.digest silently returns empty Buffer on second call instead of throwing ERR_CRYPTO_HASH_FINALIZED

Open Beginner friendly
#6,921 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
8.7k
Forks
739
Avg merge
2d 20h
Merged PRs (30d)
174

Description

### Description

Calling `hmac.digest()` a second time silently returns an empty `Buffer` (or `''`)
instead of throwing `ERR_CRYPTO_HASH_FINALIZED`, diverging from both Node.js behavior
and the existing `Hash.prototype.digest` implementation in the same file.

### Reproduction

```js
import { createHmac } from 'node:crypto';

const hmac = createHmac('sha256', 'secret');
hmac.update('data');

const first = hmac.digest('hex'); // correct HMAC
const second = hmac.digest('hex'); // should throw, but returns '' in workerd
console.log(second); // '' — silent wrong result
```

### Expected behavior (Node.js v22)

The second `hmac.digest()` call throws:

Error [ERR_CRYPTO_HASH_FINALIZED]: Digest already called

### Actual behavior (workerd)

Returns `''` (empty string) or `Buffer.from('')` silently, producing a wrong result
without any indication of the error.

### Root cause

In `src/node/internal/crypto_hash.ts`, `Hash.prototype.digest` correctly throws
`ERR_CRYPTO_HASH_FINALIZED` on a second call, but `Hmac.prototype.digest` has:

```ts
if (state[kFinalized]) {
return !outputEncoding || outputEncoding === 'buffer'
? Buffer.from('') // ← silently wrong
: '';
}
```

**Fix:** Replace the early return with `throw new ERR_CRYPTO_HASH_FINALIZED()`.

### Impact

Silent data corruption callers get an empty HMAC value thinking it's correct.

Contributor guide

Open the contributing guide

Research direction

Start in src/node/internal/crypto_hash.ts and compare Hmac.prototype.digest with the existing Hash.prototype.digest finalized-state handling. Verify the behavior with the reproduction: the first digest returns the HMAC, while a second call throws ERR_CRYPTO_HASH_FINALIZED rather than returning an empty string or Buffer.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
api, security
Issue type
Bug
Difficulty
1/5
Estimated time
Under an hour
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.