Context
server/src/middleware/auth.ts:644-652 (hasValidAdminApiKey) compares the request-supplied admin API key to process.env.ADMIN_API_KEY using ===. Surfaced by security-reviewer in PR #4207.
Risk
Low. The key is high-entropy and remote timing-attack signal across the public internet is very weak. But:
- It's a one-line hardening.
- Removes a category of question for any future security review.
Proposal
Swap the === for crypto.timingSafeEqual over equal-length Buffers. Length-mismatch handling needs to compare a dummy buffer of the correct length to keep the comparison constant-time.
```ts
import { timingSafeEqual } from 'node:crypto';
function constantTimeEqual(a: string, b: string): boolean {
const aBuf = Buffer.from(a);
const bBuf = Buffer.from(b);
if (aBuf.length !== bBuf.length) {
// Compare against a same-length dummy to keep the timing constant.
timingSafeEqual(aBuf, Buffer.alloc(aBuf.length));
return false;
}
return timingSafeEqual(aBuf, bBuf);
}
```
Files to touch
- `server/src/middleware/auth.ts` — `hasValidAdminApiKey` only.
- Add a unit test that asserts both equal-length-mismatch and length-mismatch paths return false.
Out of scope
Other API key comparisons in the codebase (registry signing keys, agent credentials, etc.). Audit those separately.
Context
server/src/middleware/auth.ts:644-652(hasValidAdminApiKey) compares the request-supplied admin API key toprocess.env.ADMIN_API_KEYusing===. Surfaced by security-reviewer in PR #4207.Risk
Low. The key is high-entropy and remote timing-attack signal across the public internet is very weak. But:
Proposal
Swap the
===forcrypto.timingSafeEqualover equal-lengthBuffers. Length-mismatch handling needs to compare a dummy buffer of the correct length to keep the comparison constant-time.```ts
import { timingSafeEqual } from 'node:crypto';
function constantTimeEqual(a: string, b: string): boolean {
const aBuf = Buffer.from(a);
const bBuf = Buffer.from(b);
if (aBuf.length !== bBuf.length) {
// Compare against a same-length dummy to keep the timing constant.
timingSafeEqual(aBuf, Buffer.alloc(aBuf.length));
return false;
}
return timingSafeEqual(aBuf, bBuf);
}
```
Files to touch
Out of scope
Other API key comparisons in the codebase (registry signing keys, agent credentials, etc.). Audit those separately.