From 491c31859580cc183d767a5a174c7990fcfc4793 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Mon, 27 Jul 2026 14:07:10 -0700 Subject: [PATCH] fix(security): suppress the CodeQL password-hash alert on sha256Hex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeQL fails #5963 (the v0.7.46 release PR) with 2 high-severity js/insufficient-password-hash alerts on packages/security/src/hash.ts. Both are false positives that surfaced now because d362e6816e added sha256Base64Url to this file — touching it made every pre-existing taint path ending here count as 'new code changed by this pull request'. The flagged lines and all their callers are unchanged. Neither taint source is a human password: - hashApiKey passes an API key built from generateSecureToken(24) — 192 bits of randomBytes. A fast digest is the right construction for indexed lookup; a slow KDF would run on every authenticated request and buy nothing against an unsearchable keyspace. - passwordSlot passes an already-encrypted value, hashed to an 8-char discriminator that invalidates deployment auth tokens when the password changes — not credential storage. User credentials never reach this helper; Better Auth owns them and applies its own KDF. Suppress with the inline lgtm comments this repo already uses for the same class of judgement (see uuidV5 in ee/workspace-forking/lib/remap/block-identity.ts), and document the invariant on sha256Hex so a future caller knows a genuine password belongs in Better Auth, not here. Only the two flagged lines are suppressed — sha256Base64Url is left unannotated so a real finding there would still surface. --- packages/security/src/hash.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) 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') }