Skip to content

fix(basic-auth): use jitter and constant-time string comparison#1283

Merged
pi0 merged 5 commits intomainfrom
fix/safer-auth
Jan 17, 2026
Merged

fix(basic-auth): use jitter and constant-time string comparison#1283
pi0 merged 5 commits intomainfrom
fix/safer-auth

Conversation

@pi0
Copy link
Copy Markdown
Member

@pi0 pi0 commented Jan 17, 2026

This PR makes basic auth utilities safer by using constant-time string comparation to prevent guessing password char by char (v8 fast-fails on first char mismatch)

Also fail error is thrown by a random jitter to make it harder.

Summary by CodeRabbit

  • Bug Fixes

    • Strengthened Basic auth: more robust handling of malformed headers and decoding errors, consistent failure responses, and added small randomized delay on failures.
    • Improved credential comparison to resist timing attacks.
  • Tests

    • Added extensive tests covering many Basic auth success/failure scenarios and the timing-safe comparison behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 17, 2026

📝 Walkthrough

Walkthrough

Reworks Basic auth flow: adds timing-safe string comparison and random jitter, tightens Base64 decoding error handling, renames an internal error helper to authFailed, and extends tests with integration and unit suites for auth behavior and timingSafeEqual.

Changes

Cohort / File(s) Summary
Security utilities
src/utils/internal/auth.ts
Adds timingSafeEqual(a: string, b: string): boolean (constant-time UTF‑8 byte comparison) and randomJitter(): Promise<void> (0–99ms delay).
Authentication refactor
src/utils/auth.ts
Reworks requireBasicAuth flow: rename autheFailedauthFailed, add try/catch for Base64 decoding, use timingSafeEqual for optional username/password checks, introduce randomJitter() before failing auth, and preserve validate hook & context population.
Integration tests
test/auth.test.ts
Adds many HTTP-level tests for Basic auth scenarios: valid/invalid Base64, missing parts, colon-in-password cases, empty credentials, non-Basic types, and sync/async custom validate function behavior.
Unit tests for utilities
test/unit/auth.test.ts
Adds comprehensive unit tests for timingSafeEqual, covering ASCII, multi-byte UTF‑8, surrogate pairs/emojis, normalization/zero-width cases, and length-difference edge cases.
Manifests
manifest_file, package.json
Minor manifest/package entries changed (lines added/removed reported).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I nibble bytes in constant time,

no twitch, no leak, no hurried rhyme.
A jittered hop, a careful try—
Base64 straight, no edges sly.
Securely, softly, authentication hops by.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: introducing jitter and constant-time string comparison for basic authentication security improvements.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov bot commented Jan 17, 2026

Codecov Report

❌ Patch coverage is 85.71429% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/utils/auth.ts 76.47% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/utils/auth.ts`:
- Line 70: The current destructuring const [username, password] =
authDecoded.split(":") drops any colons in the password; change the parsing to
split on the first colon only (e.g., find the first indexOf(":") on authDecoded
and use substring/slice to produce username and password) and handle the
missing-colon case (treat as invalid auth). Update the code around the
authDecoded parsing (the line assigning username/password) so password preserves
everything after the first colon.
- Around line 86-88: The custom validate branch in src/utils/auth.ts calls
opts.validate(username, password) and throws authFailed(event, opts?.realm)
immediately on false, causing inconsistent timing versus the username/password
failure path; change the failure path for the opts.validate false case to await
randomJitter() before throwing so it matches the jitter behavior used for
username/password checks (referencing opts.validate, authFailed, and
randomJitter).
🧹 Nitpick comments (3)
src/utils/internal/auth.ts (1)

18-24: Minor comment inconsistency.

The JSDoc states "0-100ms" but Math.floor(Math.random() * 100) produces values in range [0, 99].

📝 Suggested fix
 /**
- * Add random delay (0-100ms) to prevent timing-based credential inference.
+ * Add random delay (0-99ms) to prevent timing-based credential inference.
  */
src/utils/auth.ts (2)

58-58: Inconsistent realm parameter.

authFailed(event) is called without the realm here, while all other call sites pass opts?.realm. Consider passing the realm consistently for uniform WWW-Authenticate headers.

📝 Suggested fix
-    throw authFailed(event);
+    throw authFailed(event, opts?.realm);

112-120: Unused event parameter.

The event parameter is declared but not used in the function body. Either remove it or document the intended future use.

🧹 Suggested fix
-function authFailed(event: HTTPEvent, realm: string = "") {
+function authFailed(_event: HTTPEvent, realm: string = "") {

Or remove entirely if not needed:

-function authFailed(event: HTTPEvent, realm: string = "") {
+function authFailed(realm: string = "") {

@pi0 pi0 merged commit 4e091a6 into main Jan 17, 2026
6 checks passed
@pi0 pi0 deleted the fix/safer-auth branch January 17, 2026 10:53
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