Where: src/lib/apiKeys.ts, validateApiKey() (lines ~126-144).
What's wrong:
export function validateApiKey(key: string): ApiKey | null {
for (const apiKey of keysStore.values()) {
if (apiKey.status !== "active") continue;
if (apiKey.key === key) return apiKey;
if (apiKey.old_key && apiKey.new_key_expires_at && now < apiKey.new_key_expires_at) {
if (apiKey.old_key === key) return apiKey;
}
}
return null;
}
Both the current-key and grace-period-old-key comparisons use plain ===.
This is the same class of issue as the admin-key comparisons flagged
separately (apiKeyAuth.ts, graphql/schema.ts) — the codebase has
lib/timing-safe.ts precisely for this purpose but it isn't used here,
even though this function is on the live path for GraphQL API-key auth
(createGraphQLContext calls it directly).
Suggested fix: use timingSafeCompare(apiKey.key, key) (and likewise for
old_key) instead of ===.
Where:
src/lib/apiKeys.ts,validateApiKey()(lines ~126-144).What's wrong:
Both the current-key and grace-period-old-key comparisons use plain
===.This is the same class of issue as the admin-key comparisons flagged
separately (
apiKeyAuth.ts,graphql/schema.ts) — the codebase haslib/timing-safe.tsprecisely for this purpose but it isn't used here,even though this function is on the live path for GraphQL API-key auth
(
createGraphQLContextcalls it directly).Suggested fix: use
timingSafeCompare(apiKey.key, key)(and likewise forold_key) instead of===.