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