Attached is the debdiff Regards, Daniel
diff -Nru python-authlib-1.6.0/debian/changelog python-authlib-1.6.0/debian/changelog --- python-authlib-1.6.0/debian/changelog 2025-05-24 17:14:40.000000000 +0200 +++ python-authlib-1.6.0/debian/changelog 2026-03-02 03:57:30.000000000 +0100 @@ -1,3 +1,26 @@ +python-authlib (1.6.0-1+deb13u1) trixie; urgency=medium + + * Non-maintainer upload by the Debian LTS team. + * d/patches/CVE-2025-68158.patch: Add patch to fix CVE-2025-68158. + - The cache-backed state/request-token storage is not tied to the + initiating user session, so CSRF is possible for any attacker that has + a valid state. + * d/patches/CVE-2025-62706.patch: Add patch to fix CVE-2025-62706. + - Authlib’s JWE zip=DEF path performs unbounded DEFLATE decompression + which can lead to a DoS. + * d/patches/CVE-2025-61920.patch: Add patch to fix CVE-2025-61920. + - Authlib’s JOSE implementation accepts unbounded JWS/JWT header and + signature segments which can lead to a DoS during verification. + * d/patches/CVE-2025-59420.patch: Add patch to fix CVE-2025-59420. + - Authlib’s JWS verification accepts tokens that declare unknown critical + header parameters (crit), violating RFC 7515 “must‑understand” semantics. + An attacker can craft a signed token with a critical header that strict + verifiers reject but Authlib accepts. In mixed‑language fleets, this + enables split‑brain verification and can lead to policy bypass, replay, + or privilege escalation. + + -- Daniel Leidert <[email protected]> Mon, 02 Mar 2026 03:57:30 +0100 + python-authlib (1.6.0-1) unstable; urgency=medium * New upstream release. diff -Nru python-authlib-1.6.0/debian/gbp.conf python-authlib-1.6.0/debian/gbp.conf --- python-authlib-1.6.0/debian/gbp.conf 2025-05-24 17:14:40.000000000 +0200 +++ python-authlib-1.6.0/debian/gbp.conf 2026-03-02 03:57:30.000000000 +0100 @@ -1,6 +1,6 @@ [DEFAULT] upstream-branch = upstream -debian-branch = debian/master +debian-branch = debian/trixie upstream-tag = upstream/%(version)s debian-tag = debian/%(version)s sign-tags = True diff -Nru python-authlib-1.6.0/debian/patches/CVE-2025-59420.patch python-authlib-1.6.0/debian/patches/CVE-2025-59420.patch --- python-authlib-1.6.0/debian/patches/CVE-2025-59420.patch 1970-01-01 01:00:00.000000000 +0100 +++ python-authlib-1.6.0/debian/patches/CVE-2025-59420.patch 2026-03-02 03:57:30.000000000 +0100 @@ -0,0 +1,208 @@ +From: Hsiaoming Yang <[email protected]> +Date: Tue, 9 Sep 2025 14:47:14 +0900 +Subject: [PATCH 1/3] fix(jose): validate crit header parameters +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + + +From: Hsiaoming Yang <[email protected]> +Date: Wed, 10 Sep 2025 18:03:10 +0900 +Subject: [PATCH 2/3] fix(jose): validate crit header when deserialize + + +From: Muhammad Noman Ilyas <[email protected]> +Date: Sun, 14 Sep 2025 19:41:50 +0500 +Subject: [PATCH 3/3] fix(jose): Reject unprotected ‘crit’ and enforce type; add tests (#823) + + +Reviewed-By: Daniel Leidert <[email protected]> +Origin: https://github.com/authlib/authlib/commit/6b1813e4392eb7c168c276099ff7783b176479df +Bug: https://github.com/authlib/authlib/security/advisories/GHSA-9ggr-2464-2j32 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-59420 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2025-59420 +--- + authlib/jose/errors.py | 8 +++++++ + authlib/jose/rfc7515/jws.py | 39 +++++++++++++++++++++++++++++++++- + tests/jose/test_jws.py | 51 ++++++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 94 insertions(+), 4 deletions(-) + +diff --git a/authlib/jose/errors.py b/authlib/jose/errors.py +index e2e7444..385a866 100644 +--- a/authlib/jose/errors.py ++++ b/authlib/jose/errors.py +@@ -33,6 +33,14 @@ class InvalidHeaderParameterNameError(JoseError): + super().__init__(description=description) + + ++class InvalidCritHeaderParameterNameError(JoseError): ++ error = "invalid_crit_header_parameter_name" ++ ++ def __init__(self, name): ++ description = f"Invalid Header Parameter Name: {name}" ++ super().__init__(description=description) ++ ++ + class InvalidEncryptionAlgorithmForECDH1PUWithKeyWrappingError(JoseError): + error = "invalid_encryption_algorithm_for_ECDH_1PU_with_key_wrapping" + +diff --git a/authlib/jose/rfc7515/jws.py b/authlib/jose/rfc7515/jws.py +index 010f9b7..65a7e97 100644 +--- a/authlib/jose/rfc7515/jws.py ++++ b/authlib/jose/rfc7515/jws.py +@@ -4,6 +4,7 @@ from authlib.common.encoding import to_unicode + from authlib.common.encoding import urlsafe_b64encode + from authlib.jose.errors import BadSignatureError + from authlib.jose.errors import DecodeError ++from authlib.jose.errors import InvalidCritHeaderParameterNameError + from authlib.jose.errors import InvalidHeaderParameterNameError + from authlib.jose.errors import MissingAlgorithmError + from authlib.jose.errors import UnsupportedAlgorithmError +@@ -66,6 +67,7 @@ class JsonWebSignature: + """ + jws_header = JWSHeader(protected, None) + self._validate_private_headers(protected) ++ self._validate_crit_headers(protected) + algorithm, key = self._prepare_algorithm_key(protected, payload, key) + + protected_segment = json_b64encode(jws_header.protected) +@@ -100,6 +102,7 @@ class JsonWebSignature: + raise DecodeError("Not enough segments") from exc + + protected = _extract_header(protected_segment) ++ self._validate_crit_headers(protected) + jws_header = JWSHeader(protected, None) + + payload = _extract_payload(payload_segment) +@@ -137,6 +140,11 @@ class JsonWebSignature: + + def _sign(jws_header): + self._validate_private_headers(jws_header) ++ # RFC 7515 §4.1.11: 'crit' MUST be integrity-protected. ++ # Reject if present in unprotected header, and validate only ++ # against the protected header parameters. ++ self._reject_unprotected_crit(jws_header.header) ++ self._validate_crit_headers(jws_header.protected) + _alg, _key = self._prepare_algorithm_key(jws_header, payload, key) + + protected_segment = json_b64encode(jws_header.protected) +@@ -277,6 +285,28 @@ class JsonWebSignature: + if k not in names: + raise InvalidHeaderParameterNameError(k) + ++ def _reject_unprotected_crit(self, unprotected_header): ++ """Reject 'crit' when found in the unprotected header (RFC 7515 §4.1.11).""" ++ if unprotected_header and "crit" in unprotected_header: ++ raise InvalidHeaderParameterNameError("crit") ++ ++ def _validate_crit_headers(self, header): ++ if "crit" in header: ++ crit_headers = header["crit"] ++ # Type enforcement for robustness and predictable errors ++ if not isinstance(crit_headers, list) or not all( ++ isinstance(x, str) for x in crit_headers ++ ): ++ raise InvalidHeaderParameterNameError("crit") ++ names = self.REGISTERED_HEADER_PARAMETER_NAMES.copy() ++ if self._private_headers: ++ names = names.union(self._private_headers) ++ for k in crit_headers: ++ if k not in names: ++ raise InvalidCritHeaderParameterNameError(k) ++ elif k not in header: ++ raise InvalidCritHeaderParameterNameError(k) ++ + def _validate_json_jws(self, payload_segment, payload, header_obj, key): + protected_segment = header_obj.get("protected") + if not protected_segment: +@@ -291,7 +321,14 @@ class JsonWebSignature: + header = header_obj.get("header") + if header and not isinstance(header, dict): + raise DecodeError('Invalid "header" value') +- ++ # RFC 7515 §4.1.11: 'crit' MUST be integrity-protected. If present in ++ # the unprotected header object, reject the JWS. ++ self._reject_unprotected_crit(header) ++ ++ # Enforce must-understand semantics for names listed in protected ++ # 'crit'. This will also ensure each listed name is present in the ++ # protected header. ++ self._validate_crit_headers(protected) + jws_header = JWSHeader(protected, header) + algorithm, key = self._prepare_algorithm_key(jws_header, payload, key) + signing_input = b".".join([protected_segment, payload_segment]) +diff --git a/tests/jose/test_jws.py b/tests/jose/test_jws.py +index 4e486a8..580bbe4 100644 +--- a/tests/jose/test_jws.py ++++ b/tests/jose/test_jws.py +@@ -204,6 +204,51 @@ class JWSTest(unittest.TestCase): + s = jws.serialize(header, b"hello", "secret") + assert isinstance(s, dict) + ++ def test_validate_crit_header_with_serialize(self): ++ jws = JsonWebSignature() ++ protected = {"alg": "HS256", "kid": "1", "crit": ["kid"]} ++ jws.serialize(protected, b"hello", "secret") ++ ++ protected = {"alg": "HS256", "crit": ["kid"]} ++ with pytest.raises(errors.InvalidCritHeaderParameterNameError): ++ jws.serialize(protected, b"hello", "secret") ++ ++ protected = {"alg": "HS256", "invalid": "1", "crit": ["invalid"]} ++ with pytest.raises(errors.InvalidCritHeaderParameterNameError): ++ jws.serialize(protected, b"hello", "secret") ++ ++ def test_validate_crit_header_with_deserialize(self): ++ jws = JsonWebSignature() ++ case1 = "eyJhbGciOiJIUzI1NiIsImNyaXQiOlsia2lkIl19.aGVsbG8.RVimhJH2LRGAeHy0ZcbR9xsgKhzhxIBkHs7S_TDgWvc" ++ with pytest.raises(errors.InvalidCritHeaderParameterNameError): ++ jws.deserialize(case1, "secret") ++ ++ case2 = ( ++ "eyJhbGciOiJIUzI1NiIsImludmFsaWQiOiIxIiwiY3JpdCI6WyJpbnZhbGlkIl19." ++ "aGVsbG8.ifW_D1AQWzggrpd8npcnmpiwMD9dp5FTX66lCkYFENM" ++ ) ++ with pytest.raises(errors.InvalidCritHeaderParameterNameError): ++ jws.deserialize(case2, "secret") ++ ++ def test_unprotected_crit_rejected_in_json_serialize(self): ++ jws = JsonWebSignature() ++ protected = {"alg": "HS256", "kid": "a"} ++ # Place 'crit' in unprotected header; must be rejected ++ header = {"protected": protected, "header": {"kid": "a", "crit": ["kid"]}} ++ with pytest.raises(errors.InvalidHeaderParameterNameError): ++ jws.serialize_json(header, b"hello", "secret") ++ ++ def test_unprotected_crit_rejected_in_json_deserialize(self): ++ jws = JsonWebSignature() ++ protected = {"alg": "HS256", "kid": "a"} ++ header = {"protected": protected, "header": {"kid": "a"}} ++ data = jws.serialize_json(header, b"hello", "secret") ++ # Tamper by adding 'crit' into the unprotected header; must be rejected ++ data_tampered = dict(data) ++ data_tampered["header"] = {"kid": "a", "crit": ["kid"]} ++ with pytest.raises(errors.InvalidHeaderParameterNameError): ++ jws.deserialize_json(data_tampered, "secret") ++ + def test_ES512_alg(self): + jws = JsonWebSignature() + private_key = read_file_path("secp521r1-private.json") +@@ -229,15 +274,15 @@ class JWSTest(unittest.TestCase): + def test_deserialize_exceeds_length(self): + jws = JsonWebSignature() + value = "aa" * 256000 +- ++ + # header exceeds length + with pytest.raises(ValueError): + jws.deserialize(value + "." + value + "." + value, "") +- ++ + # payload exceeds length + with pytest.raises(ValueError): + jws.deserialize("eyJhbGciOiJIUzI1NiJ9." + value + "." + value, "") +- ++ + # signature exceeds length + with pytest.raises(ValueError): + jws.deserialize("eyJhbGciOiJIUzI1NiJ9.YQ." + value, "") diff -Nru python-authlib-1.6.0/debian/patches/CVE-2025-61920.patch python-authlib-1.6.0/debian/patches/CVE-2025-61920.patch --- python-authlib-1.6.0/debian/patches/CVE-2025-61920.patch 1970-01-01 01:00:00.000000000 +0100 +++ python-authlib-1.6.0/debian/patches/CVE-2025-61920.patch 2026-03-02 03:57:30.000000000 +0100 @@ -0,0 +1,86 @@ +From: Hsiaoming Yang <[email protected]> +Date: Thu, 2 Oct 2025 22:26:41 +0900 +Subject: [PATCH] fix(jose): add size limitation to prevent DoS + +Reviewed-By: Daniel Leidert <[email protected]> +Origin: https://github.com/authlib/authlib/commit/867e3f87b072347a1ae9cf6983cc8bbf88447e5e +Bug: https://github.com/authlib/authlib/security/advisories/GHSA-pq5p-34cr-23v9 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-61920 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2025-61920 +--- + authlib/jose/rfc7515/jws.py | 5 +++++ + authlib/jose/util.py | 6 ++++++ + tests/jose/test_jws.py | 16 ++++++++++++++++ + 3 files changed, 27 insertions(+) + +diff --git a/authlib/jose/rfc7515/jws.py b/authlib/jose/rfc7515/jws.py +index 6ec56ce..010f9b7 100644 +--- a/authlib/jose/rfc7515/jws.py ++++ b/authlib/jose/rfc7515/jws.py +@@ -33,6 +33,8 @@ class JsonWebSignature: + ] + ) + ++ MAX_CONTENT_LENGTH: int = 256000 ++ + #: Defined available JWS algorithms in the registry + ALGORITHMS_REGISTRY = {} + +@@ -87,6 +89,9 @@ class JsonWebSignature: + + .. _`Section 7.1`: https://tools.ietf.org/html/rfc7515#section-7.1 + """ ++ if len(s) > self.MAX_CONTENT_LENGTH: ++ raise ValueError("Serialization is too long.") ++ + try: + s = to_bytes(s) + signing_input, signature_segment = s.rsplit(b".", 1) +diff --git a/authlib/jose/util.py b/authlib/jose/util.py +index 3dfeec3..848b950 100644 +--- a/authlib/jose/util.py ++++ b/authlib/jose/util.py +@@ -7,6 +7,9 @@ from authlib.jose.errors import DecodeError + + + def extract_header(header_segment, error_cls): ++ if len(header_segment) > 256000: ++ raise ValueError("Value of header is too long") ++ + header_data = extract_segment(header_segment, error_cls, "header") + + try: +@@ -20,6 +23,9 @@ def extract_header(header_segment, error_cls): + + + def extract_segment(segment, error_cls, name="payload"): ++ if len(segment) > 256000: ++ raise ValueError(f"Value of {name} is too long") ++ + try: + return urlsafe_b64decode(segment) + except (TypeError, binascii.Error) as exc: +diff --git a/tests/jose/test_jws.py b/tests/jose/test_jws.py +index 2a76f8f..4e486a8 100644 +--- a/tests/jose/test_jws.py ++++ b/tests/jose/test_jws.py +@@ -225,3 +225,19 @@ class JWSTest(unittest.TestCase): + header, payload = data["header"], data["payload"] + assert payload == b"hello" + assert header["alg"] == "ES256K" ++ ++ def test_deserialize_exceeds_length(self): ++ jws = JsonWebSignature() ++ value = "aa" * 256000 ++ ++ # header exceeds length ++ with pytest.raises(ValueError): ++ jws.deserialize(value + "." + value + "." + value, "") ++ ++ # payload exceeds length ++ with pytest.raises(ValueError): ++ jws.deserialize("eyJhbGciOiJIUzI1NiJ9." + value + "." + value, "") ++ ++ # signature exceeds length ++ with pytest.raises(ValueError): ++ jws.deserialize("eyJhbGciOiJIUzI1NiJ9.YQ." + value, "") diff -Nru python-authlib-1.6.0/debian/patches/CVE-2025-62706.patch python-authlib-1.6.0/debian/patches/CVE-2025-62706.patch --- python-authlib-1.6.0/debian/patches/CVE-2025-62706.patch 1970-01-01 01:00:00.000000000 +0100 +++ python-authlib-1.6.0/debian/patches/CVE-2025-62706.patch 2026-03-02 03:57:30.000000000 +0100 @@ -0,0 +1,52 @@ +From: Hsiaoming Yang <[email protected]> +Date: Wed, 24 Sep 2025 21:38:45 +0900 +Subject: fix(jose): add max size for JWE zip=DEF decompression + +Reviewed-By: Daniel Leidert <[email protected]> +Origin: https://github.com/authlib/authlib/commit/4b5b5703394608124cd39e547cc7829feda05a13 +Bug: https://github.com/authlib/authlib/security/advisories/GHSA-g7f3-828f-7h7m +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-62706 +--- + authlib/jose/rfc7518/jwe_zips.py | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/authlib/jose/rfc7518/jwe_zips.py b/authlib/jose/rfc7518/jwe_zips.py +index fd59b33..70b1c5c 100644 +--- a/authlib/jose/rfc7518/jwe_zips.py ++++ b/authlib/jose/rfc7518/jwe_zips.py +@@ -3,20 +3,31 @@ import zlib + from ..rfc7516 import JsonWebEncryption + from ..rfc7516 import JWEZipAlgorithm + ++GZIP_HEAD = bytes([120, 156]) ++MAX_SIZE = 250 * 1024 ++ + + class DeflateZipAlgorithm(JWEZipAlgorithm): + name = "DEF" + description = "DEFLATE" + +- def compress(self, s): ++ def compress(self, s: bytes) -> bytes: + """Compress bytes data with DEFLATE algorithm.""" + data = zlib.compress(s) +- # drop gzip headers and tail ++ # https://datatracker.ietf.org/doc/html/rfc1951 ++ # since DEF is always gzip, we can drop gzip headers and tail + return data[2:-4] + +- def decompress(self, s): ++ def decompress(self, s: bytes) -> bytes: + """Decompress DEFLATE bytes data.""" +- return zlib.decompress(s, -zlib.MAX_WBITS) ++ if s.startswith(GZIP_HEAD): ++ decompressor = zlib.decompressobj() ++ else: ++ decompressor = zlib.decompressobj(-zlib.MAX_WBITS) ++ value = decompressor.decompress(s, MAX_SIZE) ++ if decompressor.unconsumed_tail: ++ raise ValueError(f"Decompressed string exceeds {MAX_SIZE} bytes") ++ return value + + + def register_jwe_rfc7518(): diff -Nru python-authlib-1.6.0/debian/patches/CVE-2025-68158.patch python-authlib-1.6.0/debian/patches/CVE-2025-68158.patch --- python-authlib-1.6.0/debian/patches/CVE-2025-68158.patch 1970-01-01 01:00:00.000000000 +0100 +++ python-authlib-1.6.0/debian/patches/CVE-2025-68158.patch 2026-03-02 03:57:30.000000000 +0100 @@ -0,0 +1,152 @@ +From: Hsiaoming Yang <[email protected]> +Date: Fri, 12 Dec 2025 16:37:44 +0900 +Subject: [PATCH] Merge commit from fork + +Reviewed-By: Daniel Leidert <[email protected]> +Origin: https://github.com/authlib/authlib/commit/2808378611dd6fb2532b189a9087877d8f0c0489 +Bug: https://github.com/authlib/authlib/security/advisories/GHSA-fg6f-75jq-6523 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-68158 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2025-68158 +--- + .../base_client/framework_integration.py | 25 +++++------ + tests/clients/test_flask/test_oauth_client.py | 48 ++++++++++++++++++++-- + 2 files changed, 58 insertions(+), 15 deletions(-) + +diff --git a/authlib/integrations/base_client/framework_integration.py b/authlib/integrations/base_client/framework_integration.py +index 726bdda..3ca43c0 100644 +--- a/authlib/integrations/base_client/framework_integration.py ++++ b/authlib/integrations/base_client/framework_integration.py +@@ -20,11 +20,9 @@ class FrameworkIntegration: + + def _clear_session_state(self, session): + now = time.time() ++ prefix = f"_state_{self.name}" + for key in dict(session): +- if "_authlib_" in key: +- # TODO: remove in future +- session.pop(key) +- elif key.startswith("_state_"): ++ if key.startswith(prefix): + value = session[key] + exp = value.get("exp") + if not exp or exp < now: +@@ -32,29 +30,32 @@ class FrameworkIntegration: + + def get_state_data(self, session, state): + key = f"_state_{self.name}_{state}" ++ session_data = session.get(key) ++ if not session_data: ++ return None + if self.cache: +- value = self._get_cache_data(key) ++ cached_value = self._get_cache_data(key) + else: +- value = session.get(key) +- if value: +- return value.get("data") ++ cached_value = session_data ++ if cached_value: ++ return cached_value.get("data") + return None + + def set_state_data(self, session, state, data): + key = f"_state_{self.name}_{state}" ++ now = time.time() + if self.cache: + self.cache.set(key, json.dumps({"data": data}), self.expires_in) ++ session[key] = {"exp": now + self.expires_in} + else: +- now = time.time() + session[key] = {"data": data, "exp": now + self.expires_in} + + def clear_state_data(self, session, state): + key = f"_state_{self.name}_{state}" + if self.cache: + self.cache.delete(key) +- else: +- session.pop(key, None) +- self._clear_session_state(session) ++ session.pop(key, None) ++ self._clear_session_state(session) + + def update_token(self, token, refresh_token=None, access_token=None): + raise NotImplementedError() +diff --git a/tests/clients/test_flask/test_oauth_client.py b/tests/clients/test_flask/test_oauth_client.py +index 8734d42..1d4f67a 100644 +--- a/tests/clients/test_flask/test_oauth_client.py ++++ b/tests/clients/test_flask/test_oauth_client.py +@@ -146,9 +146,13 @@ class FlaskOAuthTest(TestCase): + assert resp.status_code == 302 + url = resp.headers.get("Location") + assert "oauth_token=foo" in url ++ session_data = session["_state_dev_foo"] ++ assert "exp" in session_data ++ assert "data" not in session_data + + with app.test_request_context("/?oauth_token=foo"): + with mock.patch("requests.sessions.Session.send") as send: ++ session["_state_dev_foo"] = session_data + send.return_value = mock_send_value( + "oauth_token=a&oauth_token_secret=b" + ) +@@ -206,7 +210,43 @@ class FlaskOAuthTest(TestCase): + session = oauth.dev._get_oauth_client() + assert session.update_token is not None + +- def test_oauth2_authorize(self): ++ def test_oauth2_authorize_cache(self): ++ app = Flask(__name__) ++ app.secret_key = "!" ++ cache = SimpleCache() ++ oauth = OAuth(app, cache=cache) ++ client = oauth.register( ++ "dev", ++ client_id="dev", ++ client_secret="dev", ++ api_base_url="https://resource.test/api", ++ access_token_url="https://provider.test/token", ++ authorize_url="https://provider.test/authorize", ++ ) ++ with app.test_request_context(): ++ resp = client.authorize_redirect("https://client.test/callback") ++ assert resp.status_code == 302 ++ url = resp.headers.get("Location") ++ assert "state=" in url ++ state = dict(url_decode(urlparse.urlparse(url).query))["state"] ++ assert state is not None ++ session_data = session[f"_state_dev_{state}"] ++ assert "exp" in session_data ++ assert "data" not in session_data ++ ++ with app.test_request_context(path=f"/?code=a&state={state}"): ++ # session is cleared in tests ++ session[f"_state_dev_{state}"] = session_data ++ ++ with mock.patch("requests.sessions.Session.send") as send: ++ send.return_value = mock_send_value(get_bearer_token()) ++ token = client.authorize_access_token() ++ assert token["access_token"] == "a" ++ ++ with app.test_request_context(): ++ assert client.token is None ++ ++ def test_oauth2_authorize_session(self): + app = Flask(__name__) + app.secret_key = "!" + oauth = OAuth(app) +@@ -226,11 +266,13 @@ class FlaskOAuthTest(TestCase): + assert "state=" in url + state = dict(url_decode(urlparse.urlparse(url).query))["state"] + assert state is not None +- data = session[f"_state_dev_{state}"] ++ session_data = session[f"_state_dev_{state}"] ++ assert "exp" in session_data ++ assert "data" in session_data + + with app.test_request_context(path=f"/?code=a&state={state}"): + # session is cleared in tests +- session[f"_state_dev_{state}"] = data ++ session[f"_state_dev_{state}"] = session_data + + with mock.patch("requests.sessions.Session.send") as send: + send.return_value = mock_send_value(get_bearer_token()) diff -Nru python-authlib-1.6.0/debian/patches/series python-authlib-1.6.0/debian/patches/series --- python-authlib-1.6.0/debian/patches/series 2025-05-24 17:14:40.000000000 +0200 +++ python-authlib-1.6.0/debian/patches/series 2026-03-02 03:57:30.000000000 +0100 @@ -1,3 +1,7 @@ sphinx-default-theme sphinx-3rdparty-assets sphinx-install-rst +CVE-2025-68158.patch +CVE-2025-62706.patch +CVE-2025-61920.patch +CVE-2025-59420.patch
signature.asc
Description: This is a digitally signed message part

