Skip to content

fix(security): use timing-safe comparison for admin token#2185

Open
tessaherself wants to merge 2 commits intohuggingface:mainfrom
tessaherself:fix/timing-safe-admin-token
Open

fix(security): use timing-safe comparison for admin token#2185
tessaherself wants to merge 2 commits intohuggingface:mainfrom
tessaherself:fix/timing-safe-admin-token

Conversation

@tessaherself
Copy link

Summary

  • Replace === with crypto.timingSafeEqual in AdminTokenManager.checkToken()
  • Add safeCompare() helper that pads strings to equal length before constant-time comparison
  • Prevents timing attacks that could leak admin token information through response time

Changes

  • src/lib/server/adminToken.ts: Add timing-safe comparison

Test plan

  • Verify admin token login still works (?token=... URL)
  • Verify invalid tokens are still rejected

🤖 Generated with Claude Code

Replace direct string comparison (===) with crypto.timingSafeEqual
to prevent timing attacks on admin token verification. The existing
comparison leaks token length and character-by-character match info
through response time differences.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e4ee8abf78

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +9 to +10
const bufA = Buffer.from(a.padEnd(Math.max(a.length, b.length)));
const bufB = Buffer.from(b.padEnd(Math.max(a.length, b.length)));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve exact token equality in constant-time compare

Padding both inputs with padEnd() changes the semantics of token validation: tokens that differ only by trailing spaces are now treated as equal (for example, "secret" and "secret " both become the same padded buffer). In checkToken(), this can incorrectly grant admin access for a malformed token value, so the constant-time path needs to retain an explicit original-length equality check (or otherwise avoid space-padding collisions) while still preventing timing leaks.

Useful? React with 👍 / 👎.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feedback doesn't match the actual code. The safeCompare function uses an explicit length check (if (a.length !== b.length) return false;) before the timing-safe comparison — there is no padEnd anywhere in this implementation. The length gate ensures that only equal-length strings reach timingSafeEqual, which is the standard approach.

padEnd with spaces could treat "secret" and "secret " as equal.
Check lengths first (non-secret) and only then do timingSafeEqual
on equal-length buffers without padding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant