Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package distribution for openSUSE:Factory 
checked in at 2026-11-11 16:25:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/distribution (Old)
 and      /work/SRC/openSUSE:Factory/.distribution.new.3759290 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "distribution"

Wed Nov 11 16:25:42 2026 rev:26 rq:1396551 version:3.1.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/distribution/distribution.changes        
2026-11-09 16:04:55.396515951 +0100
+++ /work/SRC/openSUSE:Factory/.distribution.new.3759290/distribution.changes   
2026-11-11 16:25:43.885882891 +0100
@@ -1,0 +2,7 @@
+Tue Nov 10 16:20:52 UTC 2026 - Dirk Müller <[email protected]>
+
+- update vendor.tar to address:
+  * bsc#1288318, CVE-2026-116585,CVE-2026-116586,CVE-2026-116587:
+    multiple security issues in github.com/go-jose/go-jose before 4.1.6
+
+-------------------------------------------------------------------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ _service ++++++
--- /var/tmp/diff_new_pack.CSmtCV/_old  2026-11-11 16:25:45.094933596 +0100
+++ /var/tmp/diff_new_pack.CSmtCV/_new  2026-11-11 16:25:45.099933806 +0100
@@ -12,6 +12,7 @@
     <param name="compression">zst</param>
     <param 
name="replace">go.opentelemetry.io/otel=go.opentelemetry.io/[email protected]</param>
     <param name="replace">golang.org/x/net=golang.org/x/[email protected]</param>
+    <param 
name="replace">github.com/go-jose/go-jose/v4=github.com/go-jose/go-jose/[email protected]</param>
     <param 
name="replace">cloud.google.com/go/auth=cloud.google.com/go/[email protected]</param>
     <param 
name="replace">github.com/klauspost/compress=github.com/klauspost/[email protected]</param>
     <param 
name="replace">go.opentelemetry.io/otel/exporters/otlp/otlptrace=go.opentelemetry.io/otel/exporters/otlp/[email protected]</param>

++++++ vendor.tar.zst ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/go.mod new/go.mod
--- old/go.mod  2026-10-28 18:47:22.000000000 +0100
+++ new/go.mod  2026-11-10 17:21:45.000000000 +0100
@@ -122,6 +122,8 @@
 
 replace golang.org/x/net => golang.org/x/net v0.60.0
 
+replace github.com/go-jose/go-jose/v4 => github.com/go-jose/go-jose/v4 v4.1.6
+
 replace cloud.google.com/go/auth => cloud.google.com/go/auth v0.23.2
 
 replace github.com/klauspost/compress => github.com/klauspost/compress v1.20.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/go.sum new/go.sum
--- old/go.sum  2026-10-28 18:47:22.000000000 +0100
+++ new/go.sum  2026-11-10 17:21:45.000000000 +0100
@@ -96,8 +96,8 @@
 github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod 
h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0=
 github.com/felixge/httpsnoop v1.0.4 
h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
 github.com/felixge/httpsnoop v1.0.4/go.mod 
h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/go-jose/go-jose/v4 v4.1.4 
h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
-github.com/go-jose/go-jose/v4 v4.1.4/go.mod 
h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
+github.com/go-jose/go-jose/v4 v4.1.6 
h1:sNRkftxFJxwsILiQukqp5z83QBSmntVwmgRY7AqBDO4=
+github.com/go-jose/go-jose/v4 v4.1.6/go.mod 
h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
 github.com/go-logr/logr v1.2.2/go.mod 
h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
 github.com/go-logr/logr v1.4.4/go.mod 
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/asymmetric.go 
new/vendor/github.com/go-jose/go-jose/v4/asymmetric.go
--- old/vendor/github.com/go-jose/go-jose/v4/asymmetric.go      2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/asymmetric.go      2026-11-10 
17:21:45.000000000 +0100
@@ -21,6 +21,7 @@
        "crypto/aes"
        "crypto/ecdsa"
        "crypto/ed25519"
+       "crypto/elliptic"
        "crypto/rand"
        "crypto/rsa"
        "crypto/sha1"
@@ -195,11 +196,11 @@
 func (ctx rsaEncrypterVerifier) encrypt(cek []byte, alg KeyAlgorithm) ([]byte, 
error) {
        switch alg {
        case RSA1_5:
-               return rsa.EncryptPKCS1v15(RandReader, ctx.publicKey, cek)
+               return rsa.EncryptPKCS1v15(randReader, ctx.publicKey, cek)
        case RSA_OAEP:
-               return rsa.EncryptOAEP(sha1.New(), RandReader, ctx.publicKey, 
cek, []byte{})
+               return rsa.EncryptOAEP(sha1.New(), randReader, ctx.publicKey, 
cek, []byte{})
        case RSA_OAEP_256:
-               return rsa.EncryptOAEP(sha256.New(), RandReader, ctx.publicKey, 
cek, []byte{})
+               return rsa.EncryptOAEP(sha256.New(), randReader, ctx.publicKey, 
cek, []byte{})
        }
 
        return nil, ErrUnsupportedAlgorithm
@@ -288,9 +289,9 @@
                // TODO(https://github.com/go-jose/go-jose/issues/40): As of 
go1.20, the
                // random parameter is legacy and ignored, and it can be nil.
                // 
https://cs.opensource.google/go/go/+/refs/tags/go1.20:src/crypto/rsa/pkcs1v15.go;l=263;bpv=0;bpt=1
-               out, err = rsa.SignPKCS1v15(RandReader, ctx.privateKey, hash, 
hashed)
+               out, err = rsa.SignPKCS1v15(randReader, ctx.privateKey, hash, 
hashed)
        case PS256, PS384, PS512:
-               out, err = rsa.SignPSS(RandReader, ctx.privateKey, hash, 
hashed, &rsa.PSSOptions{
+               out, err = rsa.SignPSS(randReader, ctx.privateKey, hash, 
hashed, &rsa.PSSOptions{
                        SaltLength: rsa.PSSSaltLengthEqualsHash,
                })
        }
@@ -391,7 +392,7 @@
 
 // Get a content encryption key for ECDH-ES
 func (ctx ecKeyGenerator) genKey() ([]byte, rawHeader, error) {
-       priv, err := ecdsa.GenerateKey(ctx.publicKey.Curve, RandReader)
+       priv, err := ecdsa.GenerateKey(ctx.publicKey.Curve, randReader)
        if err != nil {
                return nil, rawHeader{}, err
        }
@@ -483,7 +484,7 @@
                return Signature{}, ErrUnsupportedAlgorithm
        }
 
-       sig, err := ctx.privateKey.Sign(RandReader, payload, crypto.Hash(0))
+       sig, err := ctx.privateKey.Sign(randReader, payload, crypto.Hash(0))
        if err != nil {
                return Signature{}, err
        }
@@ -533,7 +534,7 @@
        _, _ = hasher.Write(payload)
        hashed := hasher.Sum(nil)
 
-       r, s, err := ecdsa.Sign(RandReader, ctx.privateKey, hashed)
+       r, s, err := ecdsa.Sign(randReader, ctx.privateKey, hashed)
        if err != nil {
                return Signature{}, err
        }
@@ -571,12 +572,21 @@
        case ES256:
                keySize = 32
                hash = crypto.SHA256
+               if ctx.publicKey.Curve != elliptic.P256() {
+                       return fmt.Errorf("go-jose/go-jose: signature uses 
different algorithm than public key")
+               }
        case ES384:
                keySize = 48
                hash = crypto.SHA384
+               if ctx.publicKey.Curve != elliptic.P384() {
+                       return fmt.Errorf("go-jose/go-jose: signature uses 
different algorithm than public key")
+               }
        case ES512:
                keySize = 66
                hash = crypto.SHA512
+               if ctx.publicKey.Curve != elliptic.P521() {
+                       return fmt.Errorf("go-jose/go-jose: signature uses 
different algorithm than public key")
+               }
        default:
                return ErrUnsupportedAlgorithm
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go 
new/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go
--- old/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go 2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go 2026-11-10 
17:21:45.000000000 +0100
@@ -51,6 +51,8 @@
                hash = sha512.New384
        case 32:
                hash = sha512.New
+       default:
+               return nil, errors.New("go-jose/go-jose: invalid key size for 
CBC-HMAC")
        }
 
        return &cbcAEAD{
@@ -176,7 +178,9 @@
 
 // Remove padding
 func unpadBuffer(buffer []byte, blockSize int) ([]byte, error) {
-       if len(buffer)%blockSize != 0 {
+       // A padded buffer can't be empty because an empty input is padded with
+       // `blockSize` bytes, resulting in a non-empty ciphertext.
+       if len(buffer) == 0 || len(buffer)%blockSize != 0 {
                return nil, errors.New("go-jose/go-jose: invalid padding")
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/crypter.go 
new/vendor/github.com/go-jose/go-jose/v4/crypter.go
--- old/vendor/github.com/go-jose/go-jose/v4/crypter.go 2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/crypter.go 2026-11-10 
17:21:45.000000000 +0100
@@ -258,6 +258,10 @@
        }
 
        recipientInfo, err = makeJWERecipient(recipient.Algorithm, 
recipient.Key)
+       if err != nil {
+               return err
+       }
+
        if recipient.KeyID != "" {
                recipientInfo.keyID = recipient.KeyID
        }
@@ -270,10 +274,8 @@
                }
        }
 
-       if err == nil {
-               ctx.recipients = append(ctx.recipients, recipientInfo)
-       }
-       return err
+       ctx.recipients = append(ctx.recipients, recipientInfo)
+       return nil
 }
 
 func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) 
(recipientKeyInfo, error) {
@@ -426,6 +428,13 @@
        }
 }
 
+func validateContentEncryptionKeySize(cek []byte, cipher contentCipher) error {
+       if len(cek) != cipher.keySize() {
+               return ErrInvalidKeySize
+       }
+       return nil
+}
+
 // Decrypt and validate the object and return the plaintext. This
 // function does not support multi-recipient. If you desire multi-recipient
 // decryption use DecryptMulti instead.
@@ -490,21 +499,23 @@
        recipientHeaders := obj.mergedHeaders(&recipient)
 
        cek, err := decrypter.decryptKey(recipientHeaders, &recipient, 
generator)
-       if err == nil {
-               // Found a valid CEK -- let's try to decrypt.
-               plaintext, err = cipher.decrypt(cek, authData, parts)
+       if err != nil {
+               return nil, ErrCryptoFailure
+       }
+       err = validateContentEncryptionKeySize(cek, cipher)
+       if err != nil {
+               return nil, ErrCryptoFailure
        }
 
-       if plaintext == nil {
+       // Found a valid CEK -- let's try to decrypt.
+       plaintext, err = cipher.decrypt(cek, authData, parts)
+       if err != nil {
                return nil, ErrCryptoFailure
        }
 
-       // The "zip" header parameter may only be present in the protected 
header.
-       if comp := obj.protected.getCompression(); comp != "" {
-               plaintext, err = decompress(comp, plaintext)
-               if err != nil {
-                       return nil, fmt.Errorf("go-jose/go-jose: failed to 
decompress plaintext: %v", err)
-               }
+       plaintext, err = obj.decompress(plaintext)
+       if err != nil {
+               return nil, err
        }
 
        return plaintext, nil
@@ -559,31 +570,42 @@
        var plaintext []byte
        var headers rawHeader
 
+       if len(obj.recipients) == 0 {
+               return -1, Header{}, nil, errors.New("go-jose/go-jose: no 
recipients")
+       }
+
+       // Loop sets `err` in the function scope; don't shadow it.
        for i, recipient := range obj.recipients {
                recipientHeaders := obj.mergedHeaders(&recipient)
 
-               cek, err := decrypter.decryptKey(recipientHeaders, &recipient, 
generator)
-               if err == nil {
-                       // Found a valid CEK -- let's try to decrypt.
-                       plaintext, err = cipher.decrypt(cek, authData, parts)
-                       if err == nil {
-                               index = i
-                               headers = recipientHeaders
-                               break
-                       }
+               var cek []byte
+               cek, err = decrypter.decryptKey(recipientHeaders, &recipient, 
generator)
+               if err != nil {
+                       continue
                }
+               err = validateContentEncryptionKeySize(cek, cipher)
+               if err != nil {
+                       continue
+               }
+
+               // Found a valid CEK -- let's try to decrypt.
+               plaintext, err = cipher.decrypt(cek, authData, parts)
+               if err != nil {
+                       continue
+               }
+
+               index = i
+               headers = recipientHeaders
+               break
        }
 
-       if plaintext == nil {
+       if err != nil {
                return -1, Header{}, nil, ErrCryptoFailure
        }
 
-       // The "zip" header parameter may only be present in the protected 
header.
-       if comp := obj.protected.getCompression(); comp != "" {
-               plaintext, err = decompress(comp, plaintext)
-               if err != nil {
-                       return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: 
failed to decompress plaintext: %v", err)
-               }
+       plaintext, err = obj.decompress(plaintext)
+       if err != nil {
+               return -1, Header{}, nil, err
        }
 
        sanitized, err := headers.sanitized()
@@ -593,3 +615,22 @@
 
        return index, sanitized, plaintext, err
 }
+
+// decompress decompresses plaintext using the protected "zip" header, if 
present.
+// It returns plaintext unchanged when there is no protected header or "zip" 
value.
+func (obj JSONWebEncryption) decompress(plaintext []byte) ([]byte, error) {
+       if obj.protected == nil {
+               return plaintext, nil
+       }
+
+       comp := obj.protected.getCompression()
+       if comp == "" {
+               return plaintext, nil
+       }
+
+       plaintext, err := decompress(comp, plaintext)
+       if err != nil {
+               return nil, fmt.Errorf("go-jose/go-jose: failed to decompress 
plaintext: %v", err)
+       }
+       return plaintext, nil
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/json/scanner.go 
new/vendor/github.com/go-jose/go-jose/v4/json/scanner.go
--- old/vendor/github.com/go-jose/go-jose/v4/json/scanner.go    2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/json/scanner.go    2026-11-10 
17:21:45.000000000 +0100
@@ -140,6 +140,10 @@
        parseArrayValue         // parsing array value
 )
 
+// This limits the max nesting depth to prevent stack overflow.
+// This is permitted by https://tools.ietf.org/html/rfc7159#section-9
+const maxNestingDepth = 10000
+
 // reset prepares the scanner for use.
 // It must be called before calling s.step.
 func (s *scanner) reset() {
@@ -170,8 +174,13 @@
 }
 
 // pushParseState pushes a new parse state p onto the parse stack.
-func (s *scanner) pushParseState(p int) {
-       s.parseState = append(s.parseState, p)
+// an error state is returned if maxNestingDepth was exceeded, otherwise 
successState is returned.
+func (s *scanner) pushParseState(c byte, newParseState int, successState int) 
int {
+       s.parseState = append(s.parseState, newParseState)
+       if len(s.parseState) <= maxNestingDepth {
+               return successState
+       }
+       return s.error(c, "exceeded max depth")
 }
 
 // popParseState pops a parse state (already obtained) off the stack
@@ -211,12 +220,10 @@
        switch c {
        case '{':
                s.step = stateBeginStringOrEmpty
-               s.pushParseState(parseObjectKey)
-               return scanBeginObject
+               return s.pushParseState(c, parseObjectKey, scanBeginObject)
        case '[':
                s.step = stateBeginValueOrEmpty
-               s.pushParseState(parseArrayValue)
-               return scanBeginArray
+               return s.pushParseState(c, parseArrayValue, scanBeginArray)
        case '"':
                s.step = stateInString
                return scanBeginLiteral
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/jwe.go 
new/vendor/github.com/go-jose/go-jose/v4/jwe.go
--- old/vendor/github.com/go-jose/go-jose/v4/jwe.go     2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/jwe.go     2026-11-10 
17:21:45.000000000 +0100
@@ -153,6 +153,10 @@
        keyEncryptionAlgorithms []KeyAlgorithm,
        contentEncryption []ContentEncryption,
 ) (*JSONWebEncryption, error) {
+       if len(input) == 0 {
+               return nil, errEmptyInput
+       }
+
        var parsed rawJSONWebEncryption
        err := json.Unmarshal([]byte(input), &parsed)
        if err != nil {
@@ -198,15 +202,6 @@
                }
        }
 
-       // Note: this must be called _after_ we parse the protected header,
-       // otherwise fields from the protected header will not get picked up.
-       var err error
-       mergedHeaders := obj.mergedHeaders(nil)
-       obj.Header, err = mergedHeaders.sanitized()
-       if err != nil {
-               return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged 
headers: %v (%v)", err, mergedHeaders)
-       }
-
        if len(parsed.Recipients) == 0 {
                obj.recipients = []recipientInfo{
                        {
@@ -260,6 +255,15 @@
                }
        }
 
+       // Note: this must be called _after_ we parse the protected header,
+       // otherwise fields from the protected header will not get picked up.
+       mergedHeaders := obj.mergedHeaders(nil)
+       var err error
+       obj.Header, err = mergedHeaders.sanitized()
+       if err != nil {
+               return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged 
headers: %w", err)
+       }
+
        obj.iv = parsed.Iv.bytes()
        obj.ciphertext = parsed.Ciphertext.bytes()
        obj.tag = parsed.Tag.bytes()
@@ -291,6 +295,10 @@
        var parts [5]string
        var ok bool
 
+       if len(input) == 0 {
+               return nil, errEmptyInput
+       }
+
        for i := range 4 {
                parts[i], input, ok = strings.Cut(input, ".")
                if !ok {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/jwk.go 
new/vendor/github.com/go-jose/go-jose/v4/jwk.go
--- old/vendor/github.com/go-jose/go-jose/v4/jwk.go     2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/jwk.go     2026-11-10 
17:21:45.000000000 +0100
@@ -107,7 +107,7 @@
 
        switch key := k.Key.(type) {
        case ed25519.PublicKey:
-               raw = fromEdPublicKey(key)
+               raw, err = fromEdPublicKey(key)
        case *ecdsa.PublicKey:
                raw, err = fromEcPublicKey(key)
        case *rsa.PublicKey:
@@ -177,13 +177,29 @@
 // UnmarshalJSON reads a key from its JSON representation.
 //
 // Returns ErrUnsupportedKeyType for unrecognized or unsupported "kty" header 
values.
-func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
+//
+// Directly unmarshaling a JWK is not safe for untrusted input.
+func (k *JSONWebKey) UnmarshalJSON(data []byte) error {
+       return k.unmarshalJSON(data, true)
+}
+
+// unmarshalJSON reads a key from its JSON representation.
+//
+// If allowPrivate is false, a JWK with private key material is rejected and 
the
+// function is safe for use against untrusted input.
+func (k *JSONWebKey) unmarshalJSON(data []byte, allowPrivate bool) (err error) 
{
        var raw rawJSONWebKey
        err = json.Unmarshal(data, &raw)
        if err != nil {
                return err
        }
 
+       if !allowPrivate &&
+               (raw.K != nil || raw.D != nil || raw.P != nil || raw.Q != nil ||
+                       raw.Dp != nil || raw.Dq != nil || raw.Qi != nil) {
+               return errors.New("go-jose/go-jose: JWK contains private 
parameters")
+       }
+
        certs, err := parseCertificateChain(raw.X5c)
        if err != nil {
                return fmt.Errorf("go-jose/go-jose: failed to unmarshal x5c 
field: %s", err)
@@ -207,21 +223,29 @@
        case "EC":
                if raw.D != nil {
                        key, err = raw.ecPrivateKey()
-                       if err == nil {
-                               keyPub = key.(*ecdsa.PrivateKey).Public()
+                       if err != nil {
+                               return err
                        }
+                       keyPub = key.(*ecdsa.PrivateKey).Public()
                } else {
                        key, err = raw.ecPublicKey()
+                       if err != nil {
+                               return err
+                       }
                        keyPub = key
                }
        case "RSA":
                if raw.D != nil {
                        key, err = raw.rsaPrivateKey()
-                       if err == nil {
-                               keyPub = key.(*rsa.PrivateKey).Public()
+                       if err != nil {
+                               return err
                        }
+                       keyPub = key.(*rsa.PrivateKey).Public()
                } else {
                        key, err = raw.rsaPublicKey()
+                       if err != nil {
+                               return err
+                       }
                        keyPub = key
                }
        case "oct":
@@ -229,25 +253,28 @@
                        return errors.New("go-jose/go-jose: invalid JWK, found 
'oct' (symmetric) key with cert chain")
                }
                key, err = raw.symmetricKey()
+               if err != nil {
+                       return err
+               }
        case "OKP":
                if raw.Crv == "Ed25519" {
                        if raw.D != nil {
                                key, err = raw.edPrivateKey()
-                               if err == nil {
-                                       keyPub = 
key.(ed25519.PrivateKey).Public()
+                               if err != nil {
+                                       return err
                                }
+                               keyPub = key.(ed25519.PrivateKey).Public()
                        } else {
                                key, err = raw.edPublicKey()
+                               if err != nil {
+                                       return err
+                               }
                                keyPub = key
                        }
                }
        case "":
                // kty MUST be present
-               err = fmt.Errorf("go-jose/go-jose: missing json web key type")
-       }
-
-       if err != nil {
-               return
+               return fmt.Errorf("go-jose/go-jose: missing json web key type")
        }
 
        if key == nil {
@@ -388,11 +415,12 @@
 
 func edThumbprintInput(ed ed25519.PublicKey) (string, error) {
        crv := "Ed25519"
-       if len(ed) > 32 {
-               return "", errors.New("go-jose/go-jose: invalid elliptic key 
(too large)")
+       err := validateEd25519PublicKey(ed)
+       if err != nil {
+               return "", err
        }
        return fmt.Sprintf(edThumbprintTemplate, crv,
-               newFixedSizeBuffer(ed, 32).base64()), nil
+               newFixedSizeBuffer(ed, ed25519.PublicKeySize).base64()), nil
 }
 
 // Thumbprint computes the JWK Thumbprint of a key using the
@@ -493,23 +521,39 @@
        return true
 }
 
+// MaxRSAModulusBits is the largest RSA modulus size, in bits, that will be
+// accepted when parsing a JWK. Applications that need larger keys can raise
+// this limit.
+//
+// If modifying MaxRSAModulusBits, do it before any parsing occurs.
+var MaxRSAModulusBits = 4096
+
 func (key rawJSONWebKey) rsaPublicKey() (*rsa.PublicKey, error) {
        if key.N == nil || key.E == nil {
                return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, 
missing n/e values")
        }
 
+       n := key.N.bigInt()
+       if n.BitLen() > MaxRSAModulusBits {
+               return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, 
modulus too large")
+       }
+
        return &rsa.PublicKey{
-               N: key.N.bigInt(),
+               N: n,
                E: key.E.toInt(),
        }, nil
 }
 
-func fromEdPublicKey(pub ed25519.PublicKey) *rawJSONWebKey {
+func fromEdPublicKey(pub ed25519.PublicKey) (*rawJSONWebKey, error) {
+       err := validateEd25519PublicKey(pub)
+       if err != nil {
+               return nil, err
+       }
        return &rawJSONWebKey{
                Kty: "OKP",
                Crv: "Ed25519",
                X:   newBuffer(pub),
-       }
+       }, nil
 }
 
 func fromRsaPublicKey(pub *rsa.PublicKey) *rawJSONWebKey {
@@ -604,21 +648,36 @@
                return nil, fmt.Errorf("go-jose/go-jose: invalid Ed25519 
private key, missing %s value(s)", strings.Join(missing, ", "))
        }
 
-       privateKey := make([]byte, ed25519.PrivateKeySize)
-       copy(privateKey[0:32], key.D.bytes())
-       copy(privateKey[32:], key.X.bytes())
-       rv := ed25519.PrivateKey(privateKey)
-       return rv, nil
+       publicKey := key.X.bytes()
+       err := validateEd25519PublicKey(publicKey)
+       if err != nil {
+               return nil, err
+       }
+
+       seed := key.D.bytes()
+       if len(seed) != ed25519.SeedSize {
+               return nil, fmt.Errorf("go-jose/go-jose: invalid Ed25519 
private key, wrong length for d")
+       }
+
+       privateKey := ed25519.NewKeyFromSeed(seed)
+       derivedPublicKey := privateKey.Public().(ed25519.PublicKey)
+       if !bytes.Equal(derivedPublicKey, publicKey) {
+               return nil, errors.New("go-jose/go-jose: invalid Ed25519 
private key, x does not match d")
+       }
+
+       return privateKey, nil
 }
 
 func (key rawJSONWebKey) edPublicKey() (ed25519.PublicKey, error) {
        if key.X == nil {
                return nil, fmt.Errorf("go-jose/go-jose: invalid Ed key, 
missing x value")
        }
-       publicKey := make([]byte, ed25519.PublicKeySize)
-       copy(publicKey[0:32], key.X.bytes())
-       rv := ed25519.PublicKey(publicKey)
-       return rv, nil
+       publicKey := key.X.bytes()
+       err := validateEd25519PublicKey(publicKey)
+       if err != nil {
+               return nil, err
+       }
+       return ed25519.PublicKey(bytes.Clone(publicKey)), nil
 }
 
 func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
@@ -642,16 +701,23 @@
                return nil, fmt.Errorf("go-jose/go-jose: invalid RSA private 
key, missing %s value(s)", strings.Join(missing, ", "))
        }
 
+       n := key.N.bigInt()
+       if n.BitLen() > MaxRSAModulusBits {
+               return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, 
modulus too large")
+       }
+
+       p, q := key.P.bigInt(), key.Q.bigInt()
+       if p.BitLen()+q.BitLen() > n.BitLen()+1 || new(big.Int).Mul(p, 
q).Cmp(n) != 0 {
+               return nil, errors.New("go-jose/go-jose: invalid RSA private 
key, p * q != n")
+       }
+
        rv := &rsa.PrivateKey{
                PublicKey: rsa.PublicKey{
-                       N: key.N.bigInt(),
+                       N: n,
                        E: key.E.toInt(),
                },
-               D: key.D.bigInt(),
-               Primes: []*big.Int{
-                       key.P.bigInt(),
-                       key.Q.bigInt(),
-               },
+               D:      key.D.bigInt(),
+               Primes: []*big.Int{p, q},
        }
 
        if key.Dp != nil {
@@ -669,9 +735,17 @@
 }
 
 func fromEdPrivateKey(ed ed25519.PrivateKey) (*rawJSONWebKey, error) {
-       raw := fromEdPublicKey(ed25519.PublicKey(ed[32:]))
+       if len(ed) != ed25519.PrivateKeySize {
+               return nil, errors.New("go-jose/go-jose: invalid Ed25519 
private key length")
+       }
 
-       raw.D = newBuffer(ed[0:32])
+       publicKey := ed.Public().(ed25519.PublicKey)
+       raw, err := fromEdPublicKey(publicKey)
+       if err != nil {
+               return nil, err
+       }
+
+       raw.D = newBuffer(ed.Seed())
        return raw, nil
 }
 
@@ -810,7 +884,7 @@
        ErrJWKSKidNotFound = errors.New("go-jose/go-jose: JWK with matching kid 
not found in JWK Set")
 )
 
-func tryJWKS(key interface{}, headers ...Header) (interface{}, error) {
+func tryJWKS(key interface{}, header Header) (interface{}, error) {
        var jwks JSONWebKeySet
 
        switch jwksType := key.(type) {
@@ -823,16 +897,8 @@
                return key, nil
        }
 
-       // Determine the KID to search for from the headers.
-       var kid string
-       for _, header := range headers {
-               if header.KeyID != "" {
-                       kid = header.KeyID
-                       break
-               }
-       }
-
-       // If no KID is specified in the headers, reject.
+       // If no KID is specified in the header, reject.
+       kid := header.KeyID
        if kid == "" {
                return nil, ErrJWKSKidNotFound
        }
@@ -846,3 +912,107 @@
 
        return keys[0].Key, nil
 }
+
+// weakEd25519PublicKeys contains the low-order Ed25519 encodings accepted by
+// Go's verifier that must not be accepted as JOSE verification keys.
+var weakEd25519PublicKeys = map[[ed25519.PublicKeySize]byte]struct{}{
+       {
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       }: {},
+       {
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+       }: {},
+       {
+               0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       }: {},
+       {
+               0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+       }: {},
+       {
+               0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
+               0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
+               0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
+               0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05,
+       }: {},
+       {
+               0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
+               0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
+               0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
+               0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85,
+       }: {},
+       {
+               0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
+               0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
+               0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
+               0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a,
+       }: {},
+       {
+               0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
+               0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
+               0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
+               0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa,
+       }: {},
+       {
+               0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+       }: {},
+       {
+               0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       }: {},
+       {
+               0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+       }: {},
+       {
+               0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       }: {},
+       {
+               0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+       }: {},
+       {
+               0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       }: {},
+}
+
+func validateEd25519PublicKey(publicKey ed25519.PublicKey) error {
+       if len(publicKey) != ed25519.PublicKeySize {
+               return fmt.Errorf("go-jose/go-jose: invalid Ed25519 public key, 
wrong length for x")
+       }
+
+       var encoded [ed25519.PublicKeySize]byte
+       copy(encoded[:], publicKey)
+       _, ok := weakEd25519PublicKeys[encoded]
+       if ok {
+               return errors.New("go-jose/go-jose: invalid Ed25519 public key, 
low-order point")
+       }
+
+       return nil
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/jws.go 
new/vendor/github.com/go-jose/go-jose/v4/jws.go
--- old/vendor/github.com/go-jose/go-jose/v4/jws.go     2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/jws.go     2026-11-10 
17:21:45.000000000 +0100
@@ -22,6 +22,7 @@
        "errors"
        "fmt"
        "strings"
+       "unicode"
 
        "github.com/go-jose/go-jose/v4/json"
 )
@@ -89,12 +90,12 @@
        signature string,
        signatureAlgorithms []SignatureAlgorithm,
 ) (*JSONWebSignature, error) {
-       signature = stripWhitespace(signature)
-       if strings.HasPrefix(signature, "{") {
+       trimmed := strings.TrimLeftFunc(signature, unicode.IsSpace)
+       if strings.HasPrefix(trimmed, "{") {
                return ParseSignedJSON(signature, signatureAlgorithms)
        }
 
-       return parseSignedCompact(signature, nil, signatureAlgorithms)
+       return parseSignedCompact(stripWhitespace(signature), nil, 
signatureAlgorithms)
 }
 
 // ParseSignedCompact parses a message in JWS Compact Serialization. 
Validation fails if the JWS is
@@ -186,6 +187,10 @@
        input string,
        signatureAlgorithms []SignatureAlgorithm,
 ) (*JSONWebSignature, error) {
+       if len(input) == 0 {
+               return nil, errEmptyInput
+       }
+
        var parsed rawJSONWebSignature
        err := json.Unmarshal([]byte(input), &parsed)
        if err != nil {
@@ -270,17 +275,18 @@
                        Signature: parsed.Signature,
                }
 
+               mergedHeaders := signature.mergedHeaders()
+               alg := mergedHeaders.getSignatureAlgorithm()
+               if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
+                       return nil, newErrUnexpectedSignatureAlgorithm(alg, 
signatureAlgorithms)
+               }
+
                var err error
-               signature.Header, err = signature.mergedHeaders().sanitized()
+               signature.Header, err = mergedHeaders.sanitized()
                if err != nil {
                        return nil, err
                }
 
-               alg := SignatureAlgorithm(signature.Header.Algorithm)
-               if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
-                       return nil, newErrUnexpectedSignatureAlgorithm(alg, 
signatureAlgorithms)
-               }
-
                if signature.header != nil {
                        signature.Unprotected, err = 
signature.header.sanitized()
                        if err != nil {
@@ -318,17 +324,20 @@
                        return nil, ErrUnprotectedNonce
                }
 
-               var err error
-               obj.Signatures[i].Header, err = 
obj.Signatures[i].mergedHeaders().sanitized()
-               if err != nil {
-                       return nil, err
-               }
+               obj.Signatures[i].header = sig.Header
 
-               alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm)
+               mergedHeaders := obj.Signatures[i].mergedHeaders()
+               alg := mergedHeaders.getSignatureAlgorithm()
                if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
                        return nil, newErrUnexpectedSignatureAlgorithm(alg, 
signatureAlgorithms)
                }
 
+               var err error
+               obj.Signatures[i].Header, err = mergedHeaders.sanitized()
+               if err != nil {
+                       return nil, err
+               }
+
                if obj.Signatures[i].header != nil {
                        obj.Signatures[i].Unprotected, err = 
obj.Signatures[i].header.sanitized()
                        if err != nil {
@@ -354,7 +363,6 @@
                // Copy value of sig
                original := sig
 
-               obj.Signatures[i].header = sig.Header
                obj.Signatures[i].original = &original
        }
 
@@ -369,6 +377,10 @@
        payload []byte,
        signatureAlgorithms []SignatureAlgorithm,
 ) (*JSONWebSignature, error) {
+       if len(input) == 0 {
+               return nil, errEmptyInput
+       }
+
        protected, s, ok := strings.Cut(input, tokenDelim)
        if !ok { // no period found
                return nil, fmt.Errorf("go-jose/go-jose: compact JWS format 
must have three parts")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/jwt/claims.go 
new/vendor/github.com/go-jose/go-jose/v4/jwt/claims.go
--- old/vendor/github.com/go-jose/go-jose/v4/jwt/claims.go      2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/jwt/claims.go      2026-11-10 
17:21:45.000000000 +0100
@@ -24,6 +24,11 @@
        "github.com/go-jose/go-jose/v4/json"
 )
 
+// maxNumericDate bounds an accepted NumericDate (in seconds). It is far past
+// any real timestamp but safely below where an int64 conversion or time.Unix
+// would overflow and wrap Time() to a bogus instant.
+const maxNumericDate = 1 << 62
+
 // Claims represents public claim values (as specified in RFC 7519).
 type Claims struct {
        Issuer    string       `json:"iss,omitempty"`
@@ -69,6 +74,16 @@
                return ErrUnmarshalNumericDate
        }
 
+       // Reject values large enough to overflow either the int64 conversion 
below
+       // or time.Unix in Time(). time.Unix adds a ~62e9-second offset 
internally,
+       // so a value near the int64 limit wraps and compares as a time in the
+       // past; for "nbf" that lets a not-yet-valid token pass the not-before
+       // check instead of being rejected. maxNumericDate (2^62 seconds) is far
+       // beyond any real timestamp yet safely below both overflow points.
+       if f >= maxNumericDate || f <= -maxNumericDate {
+               return ErrUnmarshalNumericDate
+       }
+
        *n = NumericDate(f)
        return nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/jwt/errors.go 
new/vendor/github.com/go-jose/go-jose/v4/jwt/errors.go
--- old/vendor/github.com/go-jose/go-jose/v4/jwt/errors.go      2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/jwt/errors.go      2026-11-10 
17:21:45.000000000 +0100
@@ -47,7 +47,7 @@
 var ErrExpired = errors.New("go-jose/go-jose/jwt: validation failed, token is 
expired (exp)")
 
 // ErrIssuedInTheFuture indicates that the iat field is in the future.
-var ErrIssuedInTheFuture = errors.New("go-jose/go-jose/jwt: validation field, 
token issued in the future (iat)")
+var ErrIssuedInTheFuture = errors.New("go-jose/go-jose/jwt: validation failed, 
token issued in the future (iat)")
 
 // ErrInvalidContentType indicates that token requires JWT cty header.
 var ErrInvalidContentType = errors.New("go-jose/go-jose/jwt: expected content 
type to be JWT (cty header)")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/opaque.go 
new/vendor/github.com/go-jose/go-jose/v4/opaque.go
--- old/vendor/github.com/go-jose/go-jose/v4/opaque.go  2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/opaque.go  2026-11-10 
17:21:45.000000000 +0100
@@ -46,6 +46,11 @@
                return recipientSigInfo{}, ErrUnsupportedAlgorithm
        }
 
+       pk := signer.Public()
+       if pk != nil && !pk.IsPublic() {
+               return recipientSigInfo{}, ErrNotPublic
+       }
+
        return recipientSigInfo{
                sigAlg:    alg,
                publicKey: signer.Public,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/shared.go 
new/vendor/github.com/go-jose/go-jose/v4/shared.go
--- old/vendor/github.com/go-jose/go-jose/v4/shared.go  2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/shared.go  2026-11-10 
17:21:45.000000000 +0100
@@ -80,6 +80,12 @@
 
        // ErrUnsupportedCriticalHeader is returned when a header is marked 
critical but not supported by go-jose.
        ErrUnsupportedCriticalHeader = errors.New("go-jose/go-jose: unsupported 
critical header")
+
+       // errEmptyInput is returned when go-jose was asked to parse an empty 
string.
+       errEmptyInput = errors.New("go-jose/go-jose: empty input")
+
+       // ErrNotPublic indicates a private key was passed where a public key 
was expected
+       ErrNotPublic = errors.New("go-jose/go-jose: public key was unexpectedly 
not public")
 )
 
 // Key management algorithms
@@ -291,9 +297,10 @@
        if v == nil {
                return nil, nil
        }
-       var epk *JSONWebKey
-       err := json.Unmarshal(*v, &epk)
-       if err != nil {
+       // RFC 7518 Section 4.6.1.1: the "epk" header is the ephemeral public 
key
+       // of the originator. Reject private key material before parsing it.
+       epk := new(JSONWebKey)
+       if err := epk.unmarshalJSON(*v, false); err != nil {
                return nil, err
        }
        return epk, nil
@@ -319,20 +326,6 @@
        return parsed.getByteBuffer(headerTag)
 }
 
-// getJWK extracts parsed "jwk" from the raw JSON.
-func (parsed rawHeader) getJWK() (*JSONWebKey, error) {
-       v := parsed[headerJWK]
-       if v == nil {
-               return nil, nil
-       }
-       var jwk *JSONWebKey
-       err := json.Unmarshal(*v, &jwk)
-       if err != nil {
-               return nil, err
-       }
-       return jwk, nil
-}
-
 // getCritical extracts parsed "crit" from the raw JSON. If omitted, it
 // returns an empty slice.
 func (parsed rawHeader) getCritical() ([]string, error) {
@@ -418,10 +411,14 @@
                }
                switch k {
                case headerJWK:
-                       var jwk *JSONWebKey
-                       err = json.Unmarshal(*v, &jwk)
+                       // RFC 7515 Section 4.1.3 and RFC 7516 Section 4.1.5: 
the "jwk"
+                       // header is the public key that corresponds to the key 
used to
+                       // sign the JWS or encrypt the JWE. Reject private key 
material
+                       // before parsing it.
+                       jwk := new(JSONWebKey)
+                       err = jwk.unmarshalJSON(*v, false)
                        if err != nil {
-                               err = fmt.Errorf("failed to unmarshal JWK: %v: 
%#v", err, string(*v))
+                               err = fmt.Errorf("failed to unmarshal JWK: %w", 
err)
                                return
                        }
                        h.JSONWebKey = jwk
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/signing.go 
new/vendor/github.com/go-jose/go-jose/v4/signing.go
--- old/vendor/github.com/go-jose/go-jose/v4/signing.go 2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/signing.go 2026-11-10 
17:21:45.000000000 +0100
@@ -130,6 +130,8 @@
        verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) 
error
 }
 
+var errInvalidVerificationKey = errors.New("go-jose/go-jose: invalid 
verification key")
+
 type genericSigner struct {
        recipients   []recipientSigInfo
        nonceSource  NonceSource
@@ -138,11 +140,21 @@
 }
 
 type recipientSigInfo struct {
-       sigAlg    SignatureAlgorithm
+       sigAlg SignatureAlgorithm
+       // publicKey returns a synthetic JSONWebKey for the signer.
+       // For opaque signers, it calls OpaqueSigner.Public().
        publicKey func() *JSONWebKey
        signer    payloadSigner
 }
 
+// getPublicKey gets the public key, with a nil check on the func.
+func (r recipientSigInfo) getPublicKey() *JSONWebKey {
+       if r.publicKey == nil {
+               return nil
+       }
+       return r.publicKey()
+}
+
 func staticPublicKey(jwk *JSONWebKey) func() *JSONWebKey {
        return func() *JSONWebKey {
                return jwk
@@ -178,14 +190,23 @@
 func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
        switch verificationKey := verificationKey.(type) {
        case ed25519.PublicKey:
+               if len(verificationKey) == 0 {
+                       return nil, errInvalidVerificationKey
+               }
                return &edEncrypterVerifier{
                        publicKey: verificationKey,
                }, nil
        case *rsa.PublicKey:
+               if verificationKey == nil {
+                       return nil, errInvalidVerificationKey
+               }
                return &rsaEncrypterVerifier{
                        publicKey: verificationKey,
                }, nil
        case *ecdsa.PublicKey:
+               if verificationKey == nil {
+                       return nil, errInvalidVerificationKey
+               }
                return &ecEncrypterVerifier{
                        publicKey: verificationKey,
                }, nil
@@ -196,6 +217,9 @@
        case JSONWebKey:
                return newVerifier(verificationKey.Key)
        case *JSONWebKey:
+               if verificationKey == nil {
+                       return nil, errInvalidVerificationKey
+               }
                return newVerifier(verificationKey.Key)
        case OpaqueVerifier:
                return &opaqueVerifier{verifier: verificationKey}, nil
@@ -240,18 +264,18 @@
        if err != nil {
                return recipientSigInfo{}, err
        }
-       if recipient.publicKey != nil && recipient.publicKey() != nil {
+       if recipientPubKey := recipient.getPublicKey(); recipientPubKey != nil {
+               // This should be impossible, but let's check anyway.
+               if !recipientPubKey.IsPublic() {
+                       return recipientSigInfo{}, ErrNotPublic
+               }
+
                // recipient.publicKey is a JWK synthesized for embedding when 
recipientSigInfo
                // was created for the inner key (such as a RSA or ECDSA public 
key). It contains
                // the pub key for embedding, but doesn't have extra params 
like key id.
                publicKey := signingKey
-               publicKey.Key = recipient.publicKey().Key
+               publicKey.Key = recipientPubKey.Key
                recipient.publicKey = staticPublicKey(&publicKey)
-
-               // This should be impossible, but let's check anyway.
-               if !recipient.publicKey().IsPublic() {
-                       return recipientSigInfo{}, errors.New("go-jose/go-jose: 
public key was unexpectedly not public")
-               }
        }
        return recipient, nil
 }
@@ -266,7 +290,7 @@
                        headerAlgorithm: string(recipient.sigAlg),
                }
 
-               if recipient.publicKey != nil && recipient.publicKey() != nil {
+               if recipientPubKey := recipient.getPublicKey(); recipientPubKey 
!= nil {
                        // We want to embed the JWK or set the kid header, but 
not both. Having a protected
                        // header that contains an embedded JWK while also 
simultaneously containing the kid
                        // header is confusing, and at least in ACME the two 
are considered to be mutually
@@ -274,11 +298,11 @@
                        // result of the JOSE spec. We've decided that this 
library will only include one or
                        // the other to avoid this confusion.
                        //
-                       // See https://github.com/go-jose/go-jose/issues/157 
for more context.
+                       // See https://github.com/square/go-jose/issues/157 for 
more context.
                        if ctx.embedJWK {
-                               protected[headerJWK] = recipient.publicKey()
+                               protected[headerJWK] = recipientPubKey
                        } else {
-                               keyID := recipient.publicKey().KeyID
+                               keyID := recipientPubKey.KeyID
                                if keyID != "" {
                                        protected[headerKeyID] = keyID
                                }
@@ -390,7 +414,13 @@
 // The verificationKey argument must have one of the types allowed for the
 // verificationKey argument of JSONWebSignature.Verify().
 func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey 
interface{}) error {
-       key, err := tryJWKS(verificationKey, obj.headers()...)
+       if len(obj.Signatures) > 1 {
+               return errors.New("go-jose/go-jose: too many signatures in 
payload; expecting only one")
+       }
+
+       signature := obj.Signatures[0]
+
+       key, err := tryJWKS(verificationKey, signature.Header)
        if err != nil {
                return err
        }
@@ -399,12 +429,6 @@
                return err
        }
 
-       if len(obj.Signatures) > 1 {
-               return errors.New("go-jose/go-jose: too many signatures in 
payload; expecting only one")
-       }
-
-       signature := obj.Signatures[0]
-
        if signature.header != nil {
                // Per 
https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11,
                // 4.1.11. "crit" (Critical) Header Parameter
@@ -432,11 +456,11 @@
        headers := signature.mergedHeaders()
        alg := headers.getSignatureAlgorithm()
        err = verifier.verifyPayload(input, signature.Signature, alg)
-       if err == nil {
-               return nil
+       if err != nil {
+               return ErrCryptoFailure
        }
 
-       return ErrCryptoFailure
+       return nil
 }
 
 // VerifyMulti validates (one of the multiple) signatures on the object and
@@ -467,16 +491,6 @@
 // The verificationKey argument must have one of the types allowed for the
 // verificationKey argument of JSONWebSignature.Verify().
 func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, 
verificationKey interface{}) (int, Signature, error) {
-       key, err := tryJWKS(verificationKey, obj.headers()...)
-       if err != nil {
-               return -1, Signature{}, err
-       }
-       verifier, err := newVerifier(key)
-       if err != nil {
-               return -1, Signature{}, err
-       }
-
-outer:
        for i, signature := range obj.Signatures {
                if signature.header != nil {
                        // Per 
https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11,
@@ -484,20 +498,31 @@
                        // "When used, this Header Parameter MUST be integrity
                        // protected; therefore, it MUST occur only within the 
JWS
                        // Protected Header."
-                       err = signature.header.checkNoCritical()
+                       err := signature.header.checkNoCritical()
                        if err != nil {
-                               continue outer
+                               continue
                        }
                }
 
                if signature.protected != nil {
                        // Check for only supported critical headers
-                       err = 
signature.protected.checkSupportedCritical(supportedCritical)
+                       err := 
signature.protected.checkSupportedCritical(supportedCritical)
                        if err != nil {
-                               continue outer
+                               continue
                        }
                }
 
+               // If the verification key is a JWK Set, pick a key based on 
this signature's
+               // "kid" header. If no match, skip this signature.
+               key, err := tryJWKS(verificationKey, signature.Header)
+               if err != nil {
+                       continue
+               }
+               verifier, err := newVerifier(key)
+               if err != nil {
+                       continue
+               }
+
                input, err := obj.computeAuthData(payload, &signature)
                if err != nil {
                        continue
@@ -506,18 +531,12 @@
                headers := signature.mergedHeaders()
                alg := headers.getSignatureAlgorithm()
                err = verifier.verifyPayload(input, signature.Signature, alg)
-               if err == nil {
-                       return i, signature, nil
+               if err != nil {
+                       continue
                }
+
+               return i, signature, nil
        }
 
        return -1, Signature{}, ErrCryptoFailure
 }
-
-func (obj JSONWebSignature) headers() []Header {
-       headers := make([]Header, len(obj.Signatures))
-       for i, sig := range obj.Signatures {
-               headers[i] = sig.Header
-       }
-       return headers
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/symmetric.go 
new/vendor/github.com/go-jose/go-jose/v4/symmetric.go
--- old/vendor/github.com/go-jose/go-jose/v4/symmetric.go       2026-10-28 
18:47:22.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/symmetric.go       2026-11-10 
17:21:45.000000000 +0100
@@ -34,8 +34,8 @@
        josecipher "github.com/go-jose/go-jose/v4/cipher"
 )
 
-// RandReader is a cryptographically secure random number generator (stubbed 
out in tests).
-var RandReader = rand.Reader
+// randReader is a cryptographically secure random number generator (stubbed 
out in tests).
+var randReader = rand.Reader
 
 const (
        // RFC7518 recommends a minimum of 1,000 iterations:
@@ -153,7 +153,7 @@
 // getRandomSalt generates a new salt of the given size.
 func getRandomSalt(size int) ([]byte, error) {
        salt := make([]byte, size)
-       _, err := io.ReadFull(RandReader, salt)
+       _, err := io.ReadFull(randReader, salt)
        if err != nil {
                return nil, err
        }
@@ -198,7 +198,7 @@
 // Generate a random key for the given content cipher
 func (ctx randomKeyGenerator) genKey() ([]byte, rawHeader, error) {
        key := make([]byte, ctx.size)
-       _, err := io.ReadFull(RandReader, key)
+       _, err := io.ReadFull(randReader, key)
        if err != nil {
                return nil, rawHeader{}, err
        }
@@ -238,7 +238,7 @@
 
        // Initialize a new nonce
        iv := make([]byte, aead.NonceSize())
-       _, err = io.ReadFull(RandReader, iv)
+       _, err = io.ReadFull(randReader, iv)
        if err != nil {
                return nil, err
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/github.com/go-jose/go-jose/v4/tests.Containerfile 
new/vendor/github.com/go-jose/go-jose/v4/tests.Containerfile
--- old/vendor/github.com/go-jose/go-jose/v4/tests.Containerfile        
1970-01-01 01:00:00.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/tests.Containerfile        
2026-11-10 17:21:45.000000000 +0100
@@ -0,0 +1,13 @@
+# This containerfile can be used to run the go-jose tests and cli
+
+FROM golang:1.27-trixie
+ENV GOTOOLCHAIN=local
+
+COPY . /src
+WORKDIR /src
+
+# Install the jose-util cli, which will also build the library
+RUN go build -o /usr/local/bin/jose-util ./jose-util
+
+# By default, run the tests
+CMD ["go", "test", "./..."]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/github.com/go-jose/go-jose/v4/threat_model.md 
new/vendor/github.com/go-jose/go-jose/v4/threat_model.md
--- old/vendor/github.com/go-jose/go-jose/v4/threat_model.md    1970-01-01 
01:00:00.000000000 +0100
+++ new/vendor/github.com/go-jose/go-jose/v4/threat_model.md    2026-11-10 
17:21:45.000000000 +0100
@@ -0,0 +1,25 @@
+# Threat model
+
+## What this project does and where untrusted input enters
+go-jose is a Go implementation of JOSE family of algorithms.
+
+It is a library which will parse attacker-controlled data in network-reachable
+services.
+
+## Components that matter most / least
+The primary attack surface of interest is parsing and validating JWS, JWE, JWK,
+etc when this library is used to implement authentication and authorization.
+
+## How to exercise it
+Testing is primarily done by Golang unit tests, which can be run with the
+tests.Container file's default CMD.
+
+## How you rate severity
+Any authentication bypass enabled by a go-jose issue is a high+ severity.
+
+Denial-of-service attacks are of interest when the functions may be used in a 
protocol like OIDC, ACME, etc
+which could have a server processing attacker-controlled data.
+
+## Anything to leave alone
+Any bug which only affects the jose-util CLI tool, but it can be used to 
exercise the library.
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/modules.txt new/vendor/modules.txt
--- old/vendor/modules.txt      2026-10-28 18:47:22.000000000 +0100
+++ new/vendor/modules.txt      2026-11-10 17:21:45.000000000 +0100
@@ -291,7 +291,7 @@
 # github.com/felixge/httpsnoop v1.0.4
 ## explicit; go 1.13
 github.com/felixge/httpsnoop
-# github.com/go-jose/go-jose/v4 v4.1.4
+# github.com/go-jose/go-jose/v4 v4.1.4 => github.com/go-jose/go-jose/v4 v4.1.6
 ## explicit; go 1.24.0
 github.com/go-jose/go-jose/v4
 github.com/go-jose/go-jose/v4/cipher
@@ -980,6 +980,7 @@
 google.golang.org/protobuf/types/known/wrapperspb
 # go.opentelemetry.io/otel => go.opentelemetry.io/otel v1.46.0
 # golang.org/x/net => golang.org/x/net v0.60.0
+# github.com/go-jose/go-jose/v4 => github.com/go-jose/go-jose/v4 v4.1.6
 # cloud.google.com/go/auth => cloud.google.com/go/auth v0.23.2
 # github.com/klauspost/compress => github.com/klauspost/compress v1.20.2
 # go.opentelemetry.io/otel/exporters/otlp/otlptrace => 
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0

Reply via email to