Bug#1144568: trixie-pu: package nova/2:31.0.0-6+deb13u2 (CVE-2026-46448, OSSN-0101)

Thomas Goirand <[email protected]>
Newsgroups gmane.linux.debian.devel.release
Message-ID <178690677960.46418.1732767761217630255.reportbug__39020.9000486479$1786906906$gmane$org@zbuz.infomaniak.ch>
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:nova
User: [email protected]
Usertags: pu

Dear release team,

[ Reason ]
I'd like to update Nova to address CVE-2026-46448 / OSSA-2026-022
and OSSN-0101 (see bugs #1140149 and #1142113).

The security team informed me that they prefer for these fixes to be
pushed through p-u.

[ Impact ]
CVE-2026-46448 / OSSA-2026-022: Nova scheduler hint injection bypasses
Placement resource claims and scheduling constraints.

OSSN-0101: Nova console WebSocket proxy Origin allow-list poisoning.

[ Tests ]
Building the Nova package includes running 16742 tests, some of which
were added specifically for the above fixes. On top of this, we've been
running the patched pacakges (truth: in another OpenStack release) in
production. Also, I'm constantly running the upstream functional tests
suite.

[ Risks ]
Patches are very small, if one doesn't consider new tests. It's narly
one-liners.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
2 patches.

Please allow me to upload:
nova_31.0.0-6+deb13u3_source.changes
to Trixie p-u.

Cheers,

Thomas Goirand (zigo)
nova_31.0.0-6+deb13u3.debdiff (text/plain, 10.7 KB)
diff -Nru nova-31.0.0/debian/changelog nova-31.0.0/debian/changelog
--- nova-31.0.0/debian/changelog	2026-02-06 10:34:57.000000000 +0100
+++ nova-31.0.0/debian/changelog	2026-06-15 09:16:13.000000000 +0200
@@ -1,3 +1,15 @@
+nova (2:31.0.0-6+deb13u3) trixie; urgency=medium
+
+  * CVE-2026-46448 / OSSN-2026-022: Nova scheduler hint injection bypasses
+    Placement resource claims and scheduling constraints. Applied upstream
+    patch: "Strip internal _nova-prefixed scheduler hints on create"
+    (Closes: #1140149).
+  * OSSN-0101: Nova console WebSocket proxy Origin allow-list poisoning.
+    Applied upstream patch: "Fix mutating global config in websocket proxy"
+    (Closes: #1142113).
+
+ -- Thomas Goirand <[email protected]>  Mon, 15 Jun 2026 09:16:13 +0200
+
 nova (2:31.0.0-6+deb13u2) trixie-security; urgency=high
 
   * CVE-2026-24708/OSSA-2026-002: By writing a malicious QCOW header to a root
diff -Nru nova-31.0.0/debian/patches/CVE-2026-46448-stable-2025.1_Strip-internal-_nova-prefixed-scheduler-hints-on-create.patch nova-31.0.0/debian/patches/CVE-2026-46448-stable-2025.1_Strip-internal-_nova-prefixed-scheduler-hints-on-create.patch
--- nova-31.0.0/debian/patches/CVE-2026-46448-stable-2025.1_Strip-internal-_nova-prefixed-scheduler-hints-on-create.patch	1970-01-01 01:00:00.000000000 +0100
+++ nova-31.0.0/debian/patches/CVE-2026-46448-stable-2025.1_Strip-internal-_nova-prefixed-scheduler-hints-on-create.patch	2026-06-15 09:16:13.000000000 +0200
@@ -0,0 +1,65 @@
+Author: Sylvain Bauza <[email protected]>
+Date: Tue, 12 May 2026 14:31:14 +0200
+Description: CVE-2026-46448: Strip internal _nova-prefixed scheduler hints on create
+ User-supplied scheduler hints can include internal keys like
+ "_nova_check_type" which cause the scheduler to bypass Placement
+ candidate selection, request pre-filters, and resource claims.
+ This can lead to instances being created without proper resource
+ accounting.
+ .
+ Rather than rejecting the request, silently strip any _nova-prefixed
+ hints before they reach the scheduler. This is consistent with the
+ existing hints behavior of ignoring unknown ones and ensures the
+ probe attempt still costs the attacker money.
+Assisted-By: Cursor
+Change-Id: Iac4fef93bef0bab3060d40a9ea3e0ebd69a38c37
+Bug: https://bugs.launchpad.net/nova/+bug/2151252
+Bug-Debian: https://bugs.debian.org/1140149
+Signed-off-by: Sylvain Bauza <[email protected]>
+Origin: pre-OSSA mailing list
+Last-Update: 2026-06-10
+
+Index: nova/nova/compute/api.py
+===================================================================
+--- nova.orig/nova/compute/api.py
++++ nova/nova/compute/api.py
+@@ -2232,6 +2232,10 @@ class API:
+                 msg = _('The requested availability zone is not available')
+                 raise exception.InvalidRequest(msg)
+ 
++        if scheduler_hints:
++            scheduler_hints = {k: v for k, v in scheduler_hints.items()
++                               if not k.startswith('_nova')}
++
+         filter_properties = scheduler_utils.build_filter_properties(
+             scheduler_hints, forced_host, forced_node, flavor)
+ 
+Index: nova/nova/tests/unit/compute/test_api.py
+===================================================================
+--- nova.orig/nova/tests/unit/compute/test_api.py
++++ nova/nova/tests/unit/compute/test_api.py
+@@ -220,6 +220,24 @@ class _ComputeAPIUnitTestMixIn(object):
+         list_obj.obj_reset_changes()
+         return list_obj
+ 
++    @mock.patch('nova.scheduler.utils.build_filter_properties')
++    def test_create_strips_internal_scheduler_hints(self,
++                                                    mock_build_filter):
++        mock_build_filter.side_effect = (
++            test.TestingException('stop early'))
++        flavor = self._create_flavor()
++        self.assertRaises(
++            test.TestingException,
++            self.compute_api.create,
++            self.context, flavor, 'image_id',
++            scheduler_hints={
++                '_nova_check_type': 'rebuild',
++                '_nova_future': 'something',
++                'group': 'valid-group-uuid',
++            })
++        actual_hints = mock_build_filter.call_args[0][0]
++        self.assertEqual({'group': 'valid-group-uuid'}, actual_hints)
++
+     @mock.patch(
+         'nova.network.neutron.API.is_remote_managed_port',
+         new=mock.Mock(return_value=False),
diff -Nru nova-31.0.0/debian/patches/OSSN-0101_Fix_mutating_global_config_in_websocket_proxy.patch nova-31.0.0/debian/patches/OSSN-0101_Fix_mutating_global_config_in_websocket_proxy.patch
--- nova-31.0.0/debian/patches/OSSN-0101_Fix_mutating_global_config_in_websocket_proxy.patch	1970-01-01 01:00:00.000000000 +0100
+++ nova-31.0.0/debian/patches/OSSN-0101_Fix_mutating_global_config_in_websocket_proxy.patch	2026-06-15 09:16:13.000000000 +0200
@@ -0,0 +1,126 @@
+Author: Dan Smith <[email protected]>
+Date: Thu, 02 Jul 2026 10:29:26 -0700
+Description: OSSN-0101: Fix mutating global config in websocket proxy
+ The websocket proxy mutates the CONF host list with the Host header
+ from the request, which would then poison future requests and/or
+ lead to a slow resource exhaustion attack. Simply making a copy before
+ mutation avoids the issue.
+Generated-By: Claude Opus 4.6
+Bug: https://launchpad.net/bugs/2158919
+Bug-Debian: https://bugs.debian.org/1142113
+Change-Id: Ib13e479337f9b1c8b16952089d1d5f6979976b86
+Signed-off-by: Dan Smith <[email protected]>
+Origin: upstream, https://review.opendev.org/c/openstack/nova/+/995958
+Last-Update: 2026-07-15
+
+diff --git a/nova/console/websocketproxy.py b/nova/console/websocketproxy.py
+index f71b9e1..c2b4e7f 100644
+--- a/nova/console/websocketproxy.py
++++ b/nova/console/websocketproxy.py
+@@ -203,7 +203,7 @@
+                 expected_origin_hostname = e.split(']')[0][1:]
+             else:
+                 expected_origin_hostname = e.split(':')[0]
+-        expected_origin_hostnames = CONF.console.allowed_origins
++        expected_origin_hostnames = list(CONF.console.allowed_origins)
+         expected_origin_hostnames.append(expected_origin_hostname)
+         origin_url = self.headers.get('Origin')
+         # missing origin header indicates non-browser client which is OK
+diff --git a/nova/tests/unit/console/test_websocketproxy.py b/nova/tests/unit/console/test_websocketproxy.py
+index 088ed8e..8c3660b 100644
+--- a/nova/tests/unit/console/test_websocketproxy.py
++++ b/nova/tests/unit/console/test_websocketproxy.py
+@@ -658,6 +658,81 @@
+     def test_reject_open_redirect_3_slashes(self):
+         self.test_reject_open_redirect(url='///example.com/%2F..')
+ 
++    @mock.patch('nova.console.websocketproxy.NovaProxyRequestHandler.'
++                '_check_console_port')
++    @mock.patch('nova.objects.ConsoleAuthToken.validate')
++    def test_host_header_does_not_poison_allowed_origins(
++            self, validate, check_port):
++        """Verify that the Host header from one request does not persist in
++        CONF.console.allowed_origins and affect subsequent origin checks.
++
++        Regression test for bug 2158919.
++        """
++        params = {
++            'id': 1,
++            'token': '123-456-789',
++            'instance_uuid': uuids.instance,
++            'host': 'node1',
++            'port': '10000',
++            'console_type': 'novnc',
++            'access_url_base': 'https://example.net:6080'
++        }
++        validate.return_value = objects.ConsoleAuthToken(**params)
++
++        self.wh.socket.return_value = '<socket>'
++        self.wh.path = "http://127.0.0.1/?token=123-456-789"
++        self.wh.headers = self.fake_header
++
++        original_conf_origins = list(CONF.console.allowed_origins)
++
++        self.wh.new_websocket_client()
++
++        self.assertEqual(original_conf_origins,
++                         CONF.console.allowed_origins)
++
++    @mock.patch('nova.console.websocketproxy.NovaProxyRequestHandler.'
++                '_check_console_port')
++    @mock.patch('nova.objects.ConsoleAuthToken.validate')
++    def test_previous_host_does_not_bypass_origin_check(
++            self, validate, check_port):
++        """Verify that a Host header from a prior request cannot be used to
++        bypass the origin check on a subsequent request.
++
++        Regression test for bug 2158919.
++        """
++        params = {
++            'id': 1,
++            'token': '123-456-789',
++            'instance_uuid': uuids.instance,
++            'host': 'node1',
++            'port': '10000',
++            'console_type': 'novnc',
++            'access_url_base': 'https://example.net:6080'
++        }
++        validate.return_value = objects.ConsoleAuthToken(**params)
++
++        self.wh.socket.return_value = '<socket>'
++        self.wh.path = "http://127.0.0.1/?token=123-456-789"
++
++        # First request: Host header introduces evil.com
++        self.wh.headers = {
++            'cookie': 'token="123-456-789"',
++            'Origin': 'https://evil.com:6080',
++            'Host': 'evil.com:6080',
++        }
++        self.wh.new_websocket_client()
++
++        # Second request: Origin is evil.com but Host is legitimate.
++        # This must be rejected — evil.com should not have been persisted
++        # into the allow-list by the first request.
++        self.wh.headers = {
++            'cookie': 'token="123-456-789"',
++            'Origin': 'https://evil.com:6080',
++            'Host': 'example.net:6080',
++        }
++        self.assertRaises(exception.ValidationError,
++                          self.wh.new_websocket_client)
++
+     @mock.patch('nova.objects.ConsoleAuthToken.validate')
+     def test_no_compute_rpcapi_with_invalid_token(self, mock_validate):
+         """Tests that we don't create a ComputeAPI object until we actually
+diff --git a/releasenotes/notes/console-token-origin-poison-f251ab9e3f63d6bd.yaml b/releasenotes/notes/console-token-origin-poison-f251ab9e3f63d6bd.yaml
+new file mode 100644
+index 0000000..8f8c3df
+--- /dev/null
++++ b/releasenotes/notes/console-token-origin-poison-f251ab9e3f63d6bd.yaml
+@@ -0,0 +1,6 @@
++---
++security:
++  - |
++    Bug #2158919 is fixed, which involved an authenticated user able to poison
++    the server-side allowed origins list (and potentially exhaust memory by
++    extending it until failure).
diff -Nru nova-31.0.0/debian/patches/series nova-31.0.0/debian/patches/series
--- nova-31.0.0/debian/patches/series	2026-02-06 10:34:57.000000000 +0100
+++ nova-31.0.0/debian/patches/series	2026-06-15 09:16:13.000000000 +0200
@@ -7,3 +7,5 @@
 Fix-neutron-client-dict-grabbing.patch
 OSSN-0094_restrict_swap_volume_to_cinder.patch
 cve-2026-24708-make-disk.extend-pass-format-to-qemu-img-2025.1.patch
+CVE-2026-46448-stable-2025.1_Strip-internal-_nova-prefixed-scheduler-hints-on-create.patch
+OSSN-0101_Fix_mutating_global_config_in_websocket_proxy.patch
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.