diff --git a/packages/security/src/hash.ts b/packages/security/src/hash.ts index 8ce50b5f1a2..435ba2f3628 100644 --- a/packages/security/src/hash.ts +++ b/packages/security/src/hash.ts @@ -5,13 +5,28 @@ import { createHash } from 'node:crypto' * content passes as a Uint8Array/Buffer. Use for indexed lookup of sensitive * values (e.g. API key hash columns) and content-integrity receipts where the * caller only needs to verify equality without ever reversing the hash. + * + * NOT for human-chosen passwords — those are low-entropy and need a slow KDF. + * User credentials never reach this helper: Better Auth owns them and applies + * its own KDF. What does reach it is high-entropy material where a fast digest + * is the correct construction: + * + * - API keys (`sim_`/`sk-sim-` + `generateSecureToken(24)`, 192 random bits). + * A slow KDF here would buy nothing against a keyspace that cannot be + * searched, while forcing every authenticated request through it. + * - Already-encrypted values, content digests, and cache/idempotency keys. + * + * CodeQL's `js/insufficient-password-hash` flags the sink because callers pass + * arguments it name-matches as passwords (`apiKey`, `encryptedPassword`). The + * suppressions below record that judgement; keep the invariant above true, and + * route any genuine password through Better Auth rather than this function. */ export function sha256Hex(input: string | Uint8Array): string { const hash = createHash('sha256') if (typeof input === 'string') { - hash.update(input, 'utf8') + hash.update(input, 'utf8') // lgtm[js/insufficient-password-hash] } else { - hash.update(input) + hash.update(input) // lgtm[js/insufficient-password-hash] } return hash.digest('hex') }