From b00c66248d9c7fa5ac52ecd7d39bc1e8fa589f2a Mon Sep 17 00:00:00 2001 From: pefia <165939271+pefia@users.noreply.github.com> Date: Fri, 27 Mar 2026 11:28:04 +0000 Subject: [PATCH] Handle missing secret key during session save --- src/flask/sessions.py | 19 +++++++++++++------ tests/test_session_interface.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/flask/sessions.py b/src/flask/sessions.py index ad357706..1c962db3 100644 --- a/src/flask/sessions.py +++ b/src/flask/sessions.py @@ -13,6 +13,12 @@ from werkzeug.datastructures import CallbackDict from .json.tag import TaggedJSONSerializer +_missing_secret_key_err_msg = ( + "The session is unavailable because no secret " + "key was set. Set the secret_key on the " + "application to something unique and secret." +) + if t.TYPE_CHECKING: # pragma: no cover import typing_extensions as te @@ -87,11 +93,7 @@ class NullSession(SecureCookieSession): """ def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: - raise RuntimeError( - "The session is unavailable because no secret " - "key was set. Set the secret_key on the " - "application to something unique and secret." - ) + raise RuntimeError(_missing_secret_key_err_msg) __setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail del _fail @@ -370,7 +372,12 @@ class SecureCookieSessionInterface(SessionInterface): return expires = self.get_expiration_time(app, session) - val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore[union-attr] + s = self.get_signing_serializer(app) + + if s is None: + raise RuntimeError(_missing_secret_key_err_msg) + + val = s.dumps(dict(session)) response.set_cookie( name, val, diff --git a/tests/test_session_interface.py b/tests/test_session_interface.py index 5564be74..50df38ca 100644 --- a/tests/test_session_interface.py +++ b/tests/test_session_interface.py @@ -1,3 +1,5 @@ +import pytest + import flask from flask.globals import app_ctx from flask.sessions import SessionInterface @@ -26,3 +28,16 @@ def test_open_session_with_endpoint(): response = app.test_client().get("/") assert response.status_code == 200 + + +def test_save_session_without_secret_key(app): + app.secret_key = "test key" + session = app.session_interface.session_class({"foo": "bar"}) + session.modified = True + app.secret_key = None + + with pytest.raises(RuntimeError) as e: + app.session_interface.save_session(app, session, app.response_class()) + + assert e.value.args and "session is unavailable" in e.value.args[0] + assert "no secret key was set" in e.value.args[0]