Skip to content

fix: send authorization_details unescaped from the client; refuse typed-nil access-token sources - #772

Merged
osanderson merged 2 commits into
mainfrom
fix/client-rar-escape-resource-typed-nil
Nov 1, 2026
Merged

osanderson merged 2 commits into
mainfrom
fix/client-rar-escape-resource-typed-nil

Conversation

@osanderson

Copy link
Copy Markdown
Collaborator

Summary

Two Low findings left over from the security review since v0.65.1.

  • Client re-escaping of authorization_details (fix(client)). The client encoded authorization_details with json.Marshal, and requestobject.Create encoded the signed request object the same way. That escapes <, > and & inside every json.RawMessage parameter. A detail holding A&B <Ltd> reached the server as A&B <Ltd>: the same JSON value, but longer, and not the caller's own bytes, which the server now keeps byte for byte (v0.67.2). PAR (plain form or request object), CIBA and client_credentials now use strictjson.MarshalUnescaped.
  • Typed nils in resource (fix(resource)). A nil pointer in JWTAccessTokens.IssuerKeys or OpaqueAccessTokens.Store passed the == nil checks, so construction succeeded and the first request panicked. A custom resolver's AccessTokenAssurance had the same gap under AssuranceProduction; a nil Store there panicked inside NewVerifier's capability check. Each is now refused with the field and type named, as Dependencies' own fields already are, and as fix: RARSet without HTML escaping; typed-nil trust fields; RAR hook docs #766 did for the server's trust fields.

Neither is breaking: the client sends the same JSON values, and the newly refused configurations could only panic.

Tests

  • TestAuthorizationDetailsSentWithoutHTMLEscaping covers the PAR form, the PAR request object, the CIBA request object and the client_credentials form. All four fail on main.
  • TestAccessTokensRefuseTypedNilFields covers both constructors, value and pointer literals through NewVerifier, and both AccessTokenAssurance fields under production. On main, three cases fail and the declared-store case panics.
  • go test ./... passes at go1.26.10.

🤖 Generated with Claude Code

osanderson and others added 2 commits November 1, 2026 12:32
The client encoded authorization_details with json.Marshal, and
requestobject.Create encoded the whole signed request object the same
way, which escapes <, > and & in every json.RawMessage parameter too.
A detail holding "A&B <Ltd>" reached the server as & and <:
the same JSON value, but longer, and spelled differently from the
caller's own bytes, which the server now keeps byte for byte. PAR (as a
form parameter or in a request object), CIBA and client_credentials now
encode with strictjson.MarshalUnescaped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JWTAccessTokens.IssuerKeys and OpaqueAccessTokens.Store holding a nil
pointer passed their == nil checks, so NewJWTAccessTokens,
NewOpaqueAccessTokens and NewVerifier accepted them and the first
request panicked. A custom resolver's AccessTokenAssurance had the same
gap under AssuranceProduction, where a nil store panicked in the
capability check inside NewVerifier itself. Each is now refused,
naming the field and its type, as Dependencies' own fields already
are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@sonarqubecloud

sonarqubecloud Bot commented Nov 1, 2026

Copy link
Copy Markdown

@osanderson
osanderson merged commit 75480a9 into main Nov 1, 2026
27 checks passed
@osanderson
osanderson deleted the fix/client-rar-escape-resource-typed-nil branch November 1, 2026 04:55
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