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)
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

Reply via email to