Repository navigation
Conversation
Amp-Thread-ID: https://ampcode.com/threads/T-01a0eb70-d1e6-71dd-b774-7a79333b11f8 Co-authored-by: Amp <amp@ampcode.com>
414b9e0 to
4b66453
Compare
Thanks for picking this up, making sure JWK metadata is respected is a good goal. I think there is a design problem with where the check lives, though, and most of the issues below follow from it. The core issue
So on the The library already has a mechanism that binds a key to its algorithm from the trusted side. The catch is that Other findings
Suggested direction
That would address the bypass and findings 1, 2, 3 and 5 together. The case-sensitive |
Amp-Thread-ID: https://ampcode.com/threads/T-01a0eb70-d1e6-71dd-b774-7a79333b11f8 Co-authored-by: Amp <amp@ampcode.com>
Filter incompatible candidates before reusing the loader invalidation path. Keep algorithm-bearing JWKs intact for verification, and enforce usage restrictions on direct JWK verification. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a0eb70-d1e6-71dd-b774-7a79333b11f8
|
Thanks for the detailed review. I'm also using an AI assistant on this PR; the reproductions and tests reported below were run by the assistant. 4b50a36 addresses the algorithm bypass, candidate filtering, reload path, and direct-JWK usage checks. Your RSA example now rejects the RS256 signature with PS256 metadata while accepting a genuine PS256 signature. Incompatible candidates are skipped before the existing invalidation path, and I'd appreciate your feedback on three compatibility choices:
The full suite and standalone appraisal each pass with 764 examples, 0 failures, and 12 existing pending; RuboCop reports 94 files with no offenses. The new regression cases failed before the fix. Simulating the missing RSA-PSS API gives 119 examples, 0 failures, and 26 expected pending; that does not replace native legacy OpenSSL validation. Could you also approve the pending CI run for this head so the upstream matrix can run? |
Description
JWT::JWK::KeyFindercurrently returnsverify_key, dropping the selected JWK's metadata before verification. A correctly signed token can therefore verify despite incompatiblealg,use, orkey_opsmetadata.Select compatible JWKs and retain algorithm restrictions during verification:
algmust match the token's algorithm header exactly, including case, as required by RFC 7517.usemust besig.key_opsmust containverify.Omitted metadata remains allowed. Incompatible candidates are skipped, including when several keys share an identifier or
allow_nil_kidis enabled. If no compatible candidate remains, selection uses the existing loader invalidation path before raisingJWT::SignatureError. Direct JWK verification also enforcesuseandkey_ops.KeyFinder#callreturns the JWK whenalgis present, so the trusted JWK determines the actual verification algorithm, not just the token header. For example:Without
alg,callstill returns raw key material and uses the caller's allowlist as before.key_for(kid, key_field = :kid)keeps its original positional signature and raw-key return type; no new keyword is required. Compatibility note:callnow resolves JWKs directly rather than dispatching throughkey_for, so subclasses customizing token lookup should overridecall. Applications extracting raw keys themselves must enforce algorithm restrictions. Explicitnullmetadata is not treated as omission.This enforces metadata; it does not demonstrate a signature forgery or change cryptographic verification.
Regression tests cover HMAC, RSA, RSA-PSS, EC, multi-algorithm verification, mixed JWKS, loader invalidation and direct JWK usage. Latest validation on Ruby 3.1.2 / OpenSSL gem 3.0.1: the full suite and standalone appraisal each passed with 764 examples, 0 failures, and 12 existing pending. RuboCop passed (94 files, no offenses). The new review regressions failed before the fix (119 examples, 8 failures). A separate RSA check rejected the mismatched RS256 signature while accepting a genuine PS256 signature. RSA-PSS cases use the suite's existing capability guard: removing
sign_pssin scratch validation gives 119 examples, 0 failures and 26 expected pending. This simulates the missing API; native legacy OpenSSL validation remains with CI.Checklist