Repository navigation
fix: return 401 instead of 500 when the auth header is missing - #179
Merged
Merged
Conversation
timingSafeEqual called Buffer.from() on req.headers.authorization, which throws a TypeError when the header is absent, turning an unauthenticated request to /verify-semver or /unreleased into a 500. Treat a non-string value as a mismatch (still doing the dummy constant-time compare) so the routes respond 401. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ELojQikqpZ2KVGqjEeNwUe
Contributor
Author
There was a problem hiding this comment.
I reviewed this PR and didn't find any bugs. It changes the shared credential check that guards server endpoints, and CODEOWNERS covers it, so a human from the owning team should still take a look.
What was reviewed:
- The new non-string guard in
timingSafeEqual(utils/helpers.js). A missing or nullanow returns false. It runs the same dummycrypto.timingSafeEqual(bufferB, bufferB)as the length-mismatch path, so it still fails closed with matching timing. - The guard at line 218 for an unset or empty secret still runs first, so a blank secret can never match.
- The callers in server.js (lines 46 and 292) and in
verifySlackRequest(line 274) only test the boolean result, so returning false instead of throwing leads to the existing 401 path.
Extended reasoning...
The change touches timingSafeEqual in utils/helpers.js, the constant-time comparison behind the auth checks in server.js and the Slack signature check. It also adds a node:test spec for that function. The logic is small and fails closed, and the new tests cover missing-header and unset-secret inputs. However, this is security-sensitive auth and crypto code, and the CODEOWNERS file assigns every path to a review team. That is why this defers to a human instead of approving.
MarshallOfSound
approved these changes
Oct 22, 2026
MarshallOfSound
enabled auto-merge (squash)
October 22, 2026 21:14
jkleinsc
approved these changes
Oct 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Samuel Attard · Slack thread
timingSafeEqualcalledBuffer.from()onreq.headers.authorization, which throws aTypeErrorwhen the header is missing, so unauthenticated requests to/verify-semverand/unreleasedreturned 500 instead of 401. A non-string value is now treated as a mismatch (still doing the dummy constant-time compare against the secret), and a newtest/helpers.spec.jscovers the missing-header case.Generated by Claude Code