Version in base suite: 10.9.0-2 Base version: python-keystonemiddleware_10.9.0-2 Target version: python-keystonemiddleware_10.9.0-2+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/python-keystonemiddleware/python-keystonemiddleware_10.9.0-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/python-keystonemiddleware/python-keystonemiddleware_10.9.0-2+deb13u1.dsc changelog | 8 patches/CVE-2026-22797-OSSA-2026-001-Fix_privilege_escalation_via_spoofed_identity_headers.patch | 138 ++++++++++ patches/series | 1 3 files changed, 147 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmptw94tidu/python-keystonemiddleware_10.9.0-2.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmptw94tidu/python-keystonemiddleware_10.9.0-2+deb13u1.dsc: no acceptable signature found diff -Nru python-keystonemiddleware-10.9.0/debian/changelog python-keystonemiddleware-10.9.0/debian/changelog --- python-keystonemiddleware-10.9.0/debian/changelog 2025-03-28 07:41:10.000000000 +0000 +++ python-keystonemiddleware-10.9.0/debian/changelog 2026-01-15 07:57:22.000000000 +0000 @@ -1,3 +1,11 @@ +python-keystonemiddleware (10.9.0-2+deb13u1) trixie-security; urgency=medium + + * CVE-2026-22797 / OSSA-2026-001: privilege escalation via spoofed identity + headers. Applied upstream patch: Fix privilege escalation via spoofed + identity headers (Closes: #1125680). + + -- Thomas Goirand Thu, 15 Jan 2026 08:57:22 +0100 + python-keystonemiddleware (10.9.0-2) unstable; urgency=medium * Uploading to unstable. diff -Nru python-keystonemiddleware-10.9.0/debian/patches/CVE-2026-22797-OSSA-2026-001-Fix_privilege_escalation_via_spoofed_identity_headers.patch python-keystonemiddleware-10.9.0/debian/patches/CVE-2026-22797-OSSA-2026-001-Fix_privilege_escalation_via_spoofed_identity_headers.patch --- python-keystonemiddleware-10.9.0/debian/patches/CVE-2026-22797-OSSA-2026-001-Fix_privilege_escalation_via_spoofed_identity_headers.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-keystonemiddleware-10.9.0/debian/patches/CVE-2026-22797-OSSA-2026-001-Fix_privilege_escalation_via_spoofed_identity_headers.patch 2026-01-15 07:57:22.000000000 +0000 @@ -0,0 +1,138 @@ +Description: Fix privilege escalation via spoofed identity headers + The external_oauth2_token middleware did not sanitize incoming + authentication headers before processing OAuth 2.0 tokens. This + allowed an attacker to send forged identity headers (e.g., + X-Is-Admin-Project, X-Roles, X-User-Id) that would not be cleared + by the middleware, potentially enabling privilege escalation. + . + This fix adds a call to remove_auth_headers() at the start of + request processing to sanitize all incoming identity headers, + matching the secure behavior of the main auth_token middleware. +Author: Grzegorz Grasza +Date: Thu, 8 Jan 2026 14:46:19 +0100 +Bug: https://launchpad.net/bugs/2129018 +Change-Id: Idd4fe1d17a25b3064b31f454d9830242f345e018 +Bug-Debian: https://bugs.debian.org/1125680 +Origin: upstream, https://review.opendev.org/c/openstack/keystonemiddleware/+/973496 +Last-Update: 2026-01-15 + +diff --git a/keystonemiddleware/external_oauth2_token.py b/keystonemiddleware/external_oauth2_token.py +index c02cace..32fd4e4 100644 +--- a/keystonemiddleware/external_oauth2_token.py ++++ b/keystonemiddleware/external_oauth2_token.py +@@ -33,6 +33,7 @@ from keystoneauth1.loading import session as session_loading + + from keystonemiddleware._common import config + from keystonemiddleware.auth_token import _cache ++from keystonemiddleware.auth_token import _request + from keystonemiddleware.exceptions import ConfigurationError + from keystonemiddleware.exceptions import KeystoneMiddlewareException + from keystonemiddleware.i18n import _ +@@ -534,7 +535,7 @@ class ExternalAuth2Protocol(object): + **cache_kwargs) + return _cache.TokenCache(self._log, **cache_kwargs) + +- @webob.dec.wsgify() ++ @webob.dec.wsgify(RequestClass=_request._AuthTokenRequest) + def __call__(self, req): + """Handle incoming request.""" + self.process_request(req) +@@ -545,8 +546,10 @@ class ExternalAuth2Protocol(object): + """Process request. + + :param request: Incoming request +- :type request: _request.AuthTokenRequest ++ :type request: _request._AuthTokenRequest + """ ++ request.remove_auth_headers() ++ + access_token = None + if (request.authorization and + request.authorization.authtype == 'Bearer'): +diff --git a/keystonemiddleware/tests/unit/test_external_oauth2_token_middleware.py b/keystonemiddleware/tests/unit/test_external_oauth2_token_middleware.py +index d23fedb..48f8ca5 100644 +--- a/keystonemiddleware/tests/unit/test_external_oauth2_token_middleware.py ++++ b/keystonemiddleware/tests/unit/test_external_oauth2_token_middleware.py +@@ -1823,6 +1823,79 @@ class ExternalOauth2TokenMiddlewareClientSecretBasicTest( + self.assertEqual(resp.headers.get('WWW-Authenticate'), + 'Authorization OAuth 2.0 uri="%s"' % self._audience) + ++ def test_spoofed_headers_are_sanitized(self): ++ """Test that spoofed identity headers are removed and replaced. ++ ++ This test verifies the fix for a privilege escalation vulnerability ++ where an attacker could send spoofed identity headers that would not ++ be cleared by the middleware, allowing unauthorized access. ++ """ ++ conf = copy.deepcopy(self._test_conf) ++ self.set_middleware(conf=conf) ++ ++ # Use non-admin roles in the token metadata ++ non_admin_roles = 'member,reader' ++ non_admin_metadata = copy.deepcopy(self._default_metadata) ++ non_admin_metadata['roles'] = non_admin_roles ++ ++ def mock_resp(request, context): ++ return self._introspect_response( ++ request, context, ++ auth_method=self._auth_method, ++ introspect_client_id=self._test_client_id, ++ introspect_client_secret=self._test_client_secret, ++ access_token=self._token, ++ active=True, ++ metadata=non_admin_metadata ++ ) ++ ++ self.requests_mock.post(self._introspect_endpoint, ++ json=mock_resp) ++ self.requests_mock.get(self._auth_url, ++ json=VERSION_LIST_v3, ++ status_code=300) ++ ++ # Attempt to spoof multiple identity headers ++ spoofed_headers = get_authorization_header(self._token) ++ spoofed_headers.update({ ++ 'X-Identity-Status': 'Confirmed', ++ 'X-Is-Admin-Project': 'true', ++ 'X-User-Id': 'spoofed_admin_user_id', ++ 'X-User-Name': 'spoofed_admin', ++ 'X-Roles': 'admin,superuser', ++ 'X-Project-Id': 'spoofed_project_id', ++ 'X-User-Domain-Id': 'spoofed_domain_id', ++ 'X-User-Domain-Name': 'spoofed_domain', ++ }) ++ ++ resp = self.call_middleware( ++ headers=spoofed_headers, ++ expected_status=200, ++ method='GET', path='/vnfpkgm/v1/vnf_packages', ++ environ={'wsgi.input': FakeWsgiInput(FakeSocket(None))} ++ ) ++ self.assertEqual(FakeApp.SUCCESS, resp.body) ++ ++ # Verify spoofed headers were replaced with actual token values ++ env = resp.request.environ ++ ++ # X-Is-Admin-Project should not be present (not the spoofed 'true') ++ # because the token has non-admin roles and the middleware only sets ++ # this header when is_admin is true ++ self.assertNotIn('HTTP_X_IS_ADMIN_PROJECT', env) ++ ++ # User info should match the token, not the spoofed values ++ self.assertEqual(self._user_id, env['HTTP_X_USER_ID']) ++ self.assertEqual(self._user_name, env['HTTP_X_USER_NAME']) ++ self.assertEqual(self._user_domain_id, env['HTTP_X_USER_DOMAIN_ID']) ++ self.assertEqual(self._user_domain_name, env['HTTP_X_USER_DOMAIN_NAME']) ++ ++ # Roles should be from the token, not spoofed ++ self.assertEqual(non_admin_roles, env['HTTP_X_ROLES']) ++ ++ # Project info should match the token ++ self.assertEqual(self._project_id, env['HTTP_X_PROJECT_ID']) ++ + + class ExternalAuth2ProtocolTest(BaseExternalOauth2TokenMiddlewareTest): + +-- +2.52.0 + diff -Nru python-keystonemiddleware-10.9.0/debian/patches/series python-keystonemiddleware-10.9.0/debian/patches/series --- python-keystonemiddleware-10.9.0/debian/patches/series 2025-03-28 07:41:10.000000000 +0000 +++ python-keystonemiddleware-10.9.0/debian/patches/series 2026-01-15 07:57:22.000000000 +0000 @@ -1 +1,2 @@ no-intersphinx.patch +CVE-2026-22797-OSSA-2026-001-Fix_privilege_escalation_via_spoofed_identity_headers.patch