This also affects noble and stonking, and jupyter-server/JupyterLab in
addition to the classic notebook. Upstream fixed it in tornado 6.5.10.

Affected series (all published on 2026-10-22, tested today in fresh
cloud-image VMs):

  noble     python3-tornado 6.4.0-1ubuntu0.6
            python3-jupyter-server 1.23.3-2, python3-notebook 
6.4.12-2.2ubuntu1: static files return 500 (both)
  resolute  python3-tornado 6.5.4-0.1ubuntu0.2
            jupyterlab 4.0.11, python3-jupyter-server 2.17.0-1: static files 
return 500
  stonking  python3-tornado 6.5.5-5ubuntu1.1
            jupyterlab 4.4.10, python3-jupyter-server 2.20.0-3: static files 
return 500

In every case the server log shows:
  AttributeError: 'FileFindHandler' object has no attribute 
'allowed_symlink_directory'

FileFindHandler in jupyter_server (all three versions) and in notebook
6.4.12 overrides initialize() without calling
StaticFileHandler.initialize(), so the attribute added by the
CVE-2026-103263 patch is never set. On resolute, JupyterLab shows a
blank page.

Minimal reproducer (tornado only):

import os, tempfile
import tornado
from tornado import httpclient, ioloop, web

class CustomStaticHandler(web.StaticFileHandler):
    def initialize(self, path, default_filename=None):
        self.root = path
        self.default_filename = default_filename

async def main():
    root = tempfile.mkdtemp()
    open(os.path.join(root, "hello.txt"), "w").write("hello\n")
    app = web.Application([(r"/static/(.*)", CustomStaticHandler, {"path": 
root})])
    server = app.listen(0, address="127.0.0.1")
    port = list(server._sockets.values())[0].getsockname()[1]
    resp = await httpclient.AsyncHTTPClient().fetch(
        f"http://127.0.0.1:{port}/static/hello.txt";, raise_error=False)
    print("tornado", tornado.version, "->", resp.code)
    server.stop()

ioloop.IOLoop.current().run_sync(main)

It prints 500 on noble, resolute and stonking with the security update,
and 200 with resolute's 6.5.4-0.1.

Upstream fix: allowed_symlink_directory was introduced in tornado 6.5.9
and broke Jupyter. Tornado 6.5.10, released the next day (2026-09-15),
fixed it on the tornado side: the attribute gets a class-level default
of None, and validate_absolute_path() falls back to the root it is given
("self.allowed_symlink_directory or root"). The equivalent change on the
master branch is commit 344d0d43bd1227cc613b87a09338aaf51a5feb92,
mentioned above. The Ubuntu security patch carries the 6.5.9 change
without this follow-up, so backporting it to the three series should fix
all affected subclasses. (jupyter_server 2.21.1 also adapted on its
side, but fixing tornado covers every subclass, including notebook
6.4.12.)

Local workaround until an update is available: in
jupyter_server/base/handlers.py,
FileFindHandler.validate_absolute_path(), set
"self.allowed_symlink_directory = root" just before "return
super().validate_absolute_path(root, absolute_path)". Tested on
resolute: static files return 200 again, and a symlink in the static
directory that points to /etc/hostname is still rejected with 403. This
matches what jupyter_server 2.21.1 does by default.


** CVE added: https://cve.org/CVERecord?id=CVE-2026-103263

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2172317

Title:
  python3-tornado 6.5.4-0.1ubuntu0.2 breaks Jupyter Notebook

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/python-tornado/+bug/2172317/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to