Skip to content

Commit 62ba8e4

Browse files
committed
CVE-2022-24751: Clear sessions outside of the transaction.
Clearing the sessions inside the transaction makes Zulip vulnerable to a narrow window where the deleted session has not yet been committed, but has been removed from the memcached cache. During this window, a request with the session-id which has just been deleted can successfully re-fill the memcached cache, as the in-database delete is not yet committed, and thus not yet visible. After the delete transaction commits, the cache will be left with a cached session, which allows further site access until it expires (after SESSION_COOKIE_AGE seconds), is ejected from the cache due to memory pressure, or the server is upgraded. Move the session deletion outside of the transaction. Because the testsuite runs inside of a transaction, it is impossible to test this is CI; the testsuite uses the non-caching `django.contrib.sessions.backends.db` backend, regardless. The test added in this commit thus does not fail before this commit; it is merely a base expression that the session should be deleted somehow, and does not exercise the assert added in the previous commit.
1 parent 7650b5a commit 62ba8e4

File tree

2 files changed

+20
-1
lines changed

2 files changed

+20
-1
lines changed

Diff for: zerver/lib/actions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1414,7 +1414,6 @@ def do_deactivate_user(
14141414

14151415
change_user_is_active(user_profile, False)
14161416

1417-
delete_user_sessions(user_profile)
14181417
clear_scheduled_emails(user_profile.id)
14191418
revoke_invites_generated_by_user(user_profile)
14201419

@@ -1441,6 +1440,7 @@ def do_deactivate_user(
14411440
if settings.BILLING_ENABLED:
14421441
update_license_ledger_if_needed(user_profile.realm, event_time)
14431442

1443+
delete_user_sessions(user_profile)
14441444
event = dict(
14451445
type="realm_user",
14461446
op="remove",

Diff for: zerver/tests/test_users.py

+19
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import orjson
77
from django.conf import settings
88
from django.contrib.contenttypes.models import ContentType
9+
from django.contrib.sessions.models import Session
910
from django.core.exceptions import ValidationError
1011
from django.test import override_settings
1112
from django.utils.timezone import now as timezone_now
@@ -1570,6 +1571,24 @@ def test_revoke_invites(self) -> None:
15701571
).expiry_date
15711572
)
15721573

1574+
def test_clear_sessions(self) -> None:
1575+
user = self.example_user("hamlet")
1576+
self.login_user(user)
1577+
session_key = self.client.session.session_key
1578+
self.assertTrue(session_key)
1579+
1580+
result = self.client_get("/json/users")
1581+
self.assert_json_success(result)
1582+
self.assertEqual(Session.objects.filter(pk=session_key).count(), 1)
1583+
1584+
do_deactivate_user(user, acting_user=None)
1585+
self.assertEqual(Session.objects.filter(pk=session_key).count(), 0)
1586+
1587+
result = self.client_get("/json/users")
1588+
self.assert_json_error(
1589+
result, "Not logged in: API authentication or user session required", 401
1590+
)
1591+
15731592
def test_clear_scheduled_jobs(self) -> None:
15741593
user = self.example_user("hamlet")
15751594
send_future_email(

0 commit comments

Comments
 (0)