Skip to content

fix(resource): refuse a request with more than one Authorization header - #513

Merged
osanderson merged 1 commit into
mainfrom
fix/resource-repeated-authorization
Oct 2, 2026
Merged

osanderson merged 1 commit into
mainfrom
fix/resource-repeated-authorization

Conversation

@osanderson

Copy link
Copy Markdown
Collaborator

Summary

This fixes the pre-release security review's L2. resource.VerifyRequestFromHTTP (#504, unreleased) used r.Header.Get("Authorization"), which silently takes the first of several headers, and net/http doesn't reject repeats. If a proxy, gateway or WAF in front acts on a different one (the last, or a merged value), it and the resource server disagree about which credential the request carried.

It was also inconsistent with existing behaviour:

  • the same helper already refuses more than one DPoP header (RFC 9449);
  • the client's backchannel notification endpoint already refuses repeated Authorization headers (client/backchannel_notification.go).

Fix:

  • VerifyRequestFromHTTP marks a request with more than one Authorization header, using an unexported field on VerifyRequest, so the struct's public shape doesn't change.
  • Verify refuses a marked request with a 400 invalid_request ("multiple Authorization headers are not permitted"). The refusal comes after the method and URL checks, before the scheme is parsed.
  • The Authorization field's doc now says the header isn't a list (RFC 9110 §5.3). An adapter filling the struct itself must refuse repeats first rather than pass one on.

It isn't breaking: one header behaves as before.

Tests

  • TestVerifyRefusesRepeatedAuthorization: through VerifyRequestFromHTTP and Verify, one header verifies, and two headers (DPoP … + Bearer other) give a 400 invalid_request *resource.Error.
  • Mutation check: never setting the mark fails the test.
  • Other checks:
    • go test -race ./resource/... ./serverresource/... passes.
    • golangci-lint is clean.
    • All demo modules' tests pass.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Oct 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

VerifyRequestFromHTTP read the Authorization header with Header.Get,
which silently takes the first of several, and net/http doesn't
reject repeats. A proxy or gateway in front that acts on another one
(the last, or a merged value) would then disagree with the resource
server about which credential the request carried. It already refused
more than one DPoP header, and the client's backchannel notification
endpoint refuses repeated Authorization headers.

VerifyRequestFromHTTP now marks such a request, and Verify refuses it
with a 400 invalid_request. The Authorization field's doc tells an
adapter that fills the struct itself to refuse repeats first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@osanderson
osanderson force-pushed the fix/resource-repeated-authorization branch from ce91ae4 to 17dc93b Compare October 2, 2026 06:31
@sonarqubecloud

sonarqubecloud Bot commented Oct 2, 2026

Copy link
Copy Markdown

@osanderson
osanderson merged commit 0db0d49 into main Oct 2, 2026
17 checks passed
@osanderson
osanderson deleted the fix/resource-repeated-authorization branch October 2, 2026 06:34
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