Repository navigation
[patch] Reject JWT segments outside the unpadded base64url alphabet - #409
Merged
Merged
Conversation
IsJwtTokenAttribute mapped '-'/'_' to '+'/'/' and handed the segment to Convert.FromBase64String, which skips whitespace and accepts '+', '/' and '=' padding. Tokens such as "eyJh bGci OiJI UzI1 NiJ9.eyJzdWIiOiIxIn0.sig" and "e30=.e30=.x" therefore validated and were stored verbatim. Every segment, signature included, must now use only A-Z, a-z, 0-9, '-' and '_'. Fixes #329 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LoEzLXruuTHCcJnXtVa49Z
|
This was referenced Oct 9, 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.



Fixes #329
What was wrong
IsJwtTokenAttribute.DecodesToJsonObjectmapped-/_to+//and passed the result toConvert.FromBase64String. That call skips whitespace and accepts+,/and=, none of which are in the base64url alphabet (RFC 7515 §2 also forbids padding). BecauseJwtTokenstores the value verbatim, malformed tokens were accepted and kept:eyJh bGci OiJI UzI1 NiJ9.eyJzdWIiOiIxIn0.sig, which has spaces in the headere30=.e30=.x, which uses standard-base64 paddingChange (
Semantics.Strings.Identifiers)IsBase64UrlAlphabetcheck requires every character to beA-Z,a-z,0-9,-or_. It runs on the header and payload before decoding, and on the signature segment. The signature may still be empty foralg=none.length % 4 == 1rejection stays, so the issue's "reject a segment whose length is 1 mod 4" criterion is still covered.IsJwtTokenAttributeandJwtToken, and the package README's rules table, now say the segments are unpadded base64url.Tests (
JwtTokenTests)Create_SegmentWithWhitespace_Throws: spaces in the header, spaces in the payload, and a newline at the end of the headerCreate_SegmentWithPadding_Throws:e30=.e30=.xfrom the issue, a padded payload only, and a padded signatureCreate_SegmentWithStandardBase64OrOtherCharacters_Throws:+and/in the payload, and+,/and a space in the signatureCreate_UnpaddedBase64UrlSegments_Succeeds: a short valid token still passesalg=nonevectors are unchanged and still pass.Verification
IsJwtTokenAttribute.csreverted, 7 of the new cases fail. The others (a payload with spaces, a header ending in\n, and+//in the payload) were already rejected by the decoder and stay in as guards. With the fix, all 22JwtTokenTestspass.Semantics.Testsuite passes on net10.0: 1492 passed, 0 failed, 8 skipped (the same 8 are skipped onmain).Semantics.Strings.Identifiersbuilds with the local Sonar analyzers (.sonarlint/sonar-local.props) with 0 warnings. The first version used aforeachloop, which tripped S3267, so the check usesAllinstead.🤖 Generated with Claude Code
https://claude.ai/code/session_01LoEzLXruuTHCcJnXtVa49Z
Generated by Claude Code