Skip to content

jwt_authn: handle comma-joined header values - #48517

Open
akonradi wants to merge 4 commits into
envoyproxy:mainfrom
akonradi:abakon/jwt-extractor-rfc9110-comma-list
Open

akonradi wants to merge 4 commits into
envoyproxy:mainfrom
akonradi:abakon/jwt-extractor-rfc9110-comma-list

Conversation

@akonradi

Copy link
Copy Markdown
Contributor

Commit Message:
RFC 9110 Section 5.3 mandates that header fields sent as a single line
with comma-joined values be treated as equivalent to the same field sent
on multiple header lines. The JWT extractor already handled the
multiple-header-lines form (iterating each physical header occurrence)
but took a single comma-joined header line as one opaque value, so e.g.
"Authorization: Bearer , Bearer " extracted a single,
invalid token instead of two valid ones.

Additional Description:
Found this by breaking JWT handling by a well-known header registration. The registered header appeared in a from_headers config. Registering it caused Envoy to collapse multiple values, which caused JWT extraction to barf.

AI disclosure: the author wrote this PR with assistance of AI tools but takes responsibility for the contents.

Risk Level: med, changes JWT header parsing
Testing: ran unit tests
Docs Changes: n/a
Release Notes: none
Platform Specific Features: none

RFC 9110 Section 5.3 mandates that header fields sent as a single line
with comma-joined values be treated as equivalent to the same field sent
on multiple header lines. The extractor already handled the
multiple-header-lines form (iterating each physical header occurrence)
but took a single comma-joined header line as one opaque value, so e.g.
"Authorization: Bearer <jwt1>, Bearer <jwt2>" extracted a single,
invalid token instead of two valid ones.

- For headers without a value_prefix, split the raw value on commas,
  mirroring how repeated header lines are already handled.
- For headers with a value_prefix, find every occurrence of the prefix
  within the header line and bound each extracted token at the next
  occurrence, so repeated credentials of the same scheme split cleanly
  while a single occurrence (the common case, and existing
  flexible-match configs that use commas as part of one credential's
  own syntax) keeps its historical run-to-end-of-value behavior.

Signed-off-by: Alex Bakon <abakon@netflix.com>
@akonradi

Copy link
Copy Markdown
Contributor Author

This PR took pains to keep the existing handling of ,suffix but that probably shouldn't be allowed since it's ambiguous with header concatenation. I don't know how often that's used but ideally it'd be migrated to something like ; instead.

agrawroh
agrawroh previously approved these changes Nov 4, 2026
@agrawroh

agrawroh commented Nov 4, 2026

Copy link
Copy Markdown
Member

/retest

Signed-off-by: Rohit Agrawal <rohit.agrawal@databricks.com>
@agrawroh
agrawroh enabled auto-merge (squash) November 4, 2026 06:46
@agrawroh
agrawroh disabled auto-merge November 4, 2026 06:46
@agrawroh

agrawroh commented Nov 4, 2026

Copy link
Copy Markdown
Member

I'll also run this by @wbpcode once.

@agrawroh agrawroh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@akonradi I discussed this with @wbpcode offline. We believe that some clients out their might still be relying on the old behavior. Could you please add a Runtime Guard for it so that people get time to adapt to this "correct" behavior and we don't hard break them?

@agrawroh

agrawroh commented Nov 4, 2026

Copy link
Copy Markdown
Member

/wait

@wbpcode

wbpcode commented Nov 4, 2026

Copy link
Copy Markdown
Member

A defensive runtime flag. Considering the runtime flag check is not that cheap as I expected before, may could fetch the flag value and store it at the ExtractorImpl.

Latch it at filter construction time for efficiency.

Signed-off-by: Alex Bakon <abakon@netflix.com>
@akonradi

akonradi commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

SGTM, done. While I've got y'all, WDYT of the switch I proposed above from , to ; for adding an uninterpreted suffix? Also would need to be guarded, obviously, but I don't have a feel for how "standard" the existing behavior is or who's using it.

@repokitteh-read-only

Copy link
Copy Markdown

CC @envoyproxy/runtime-guard-changes: FYI only for changes made to (source/common/runtime/runtime_features.cc).

🐱

Caused by: #48517 was synchronize by akonradi.

see: more, trace.

@wbpcode

wbpcode commented Nov 4, 2026

Copy link
Copy Markdown
Member

WDYT of the switch I proposed above from , to ; for adding an uninterpreted suffix? Also would need to be guarded, obviously, but I don't have a feel for how "standard" the existing behavior is or who's using it.

Note, no matter ,suffix or ;suffix, it’s an invalid token and should result in a 401 before? If we split the value based on , directly, seems some previous invalid token will become valid in new code path.
Although TBH, I think it never been considered before, but it's a vague behavior change.

cc @agrawroh

@akonradi

akonradi commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

That behavior was added in #6384, so definitely intentional, but not necessarily still used. I think the minimal change would be to keep the extra functionality but narrow the set of non-base64 characters allowed to exclude ,.

@akonradi

akonradi commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

/retest

Signed-off-by: Alex Bakon <abakon@netflix.com>
@akonradi
akonradi force-pushed the abakon/jwt-extractor-rfc9110-comma-list branch from 7e3a074 to 76cae56 Compare November 4, 2026 15:28

This branch has not been deployed

No deployments
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.

3 participants