From 88bce0abbc0813da33c8bc212971b126ec7f1813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Mare=C5=A1?= Date: Wed, 13 May 2026 16:33:49 +0200 Subject: [PATCH] Security: Fix checking of admin tokens in CWS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the login endpoint of the CWS API was called with an admin token, but no admin token was configured, login succeeded. This allowed attackers to impersonate any CWS user in CMS instances with no admin token configured. Thanks to Samet Akıllı for reporting the issue. --- cms/server/contest/authentication.py | 7 +++++-- .../unit_tests/server/contest/authentication_test.py | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cms/server/contest/authentication.py b/cms/server/contest/authentication.py index 1e8779a049..2a45e96edd 100644 --- a/cms/server/contest/authentication.py +++ b/cms/server/contest/authentication.py @@ -123,8 +123,11 @@ def log_failed_attempt(msg, *args): return None, None if admin_token != "": - if (config.contest_web_server.contest_admin_token is not None - and admin_token != config.contest_web_server.contest_admin_token): + if config.contest_web_server.contest_admin_token is None: + log_failed_attempt("admin token not configured") + return None, None + + if admin_token != config.contest_web_server.contest_admin_token: log_failed_attempt("invalid admin token") return None, None diff --git a/cmstestsuite/unit_tests/server/contest/authentication_test.py b/cmstestsuite/unit_tests/server/contest/authentication_test.py index 82b6b7cf8a..cdda6a043c 100755 --- a/cmstestsuite/unit_tests/server/contest/authentication_test.py +++ b/cmstestsuite/unit_tests/server/contest/authentication_test.py @@ -165,6 +165,10 @@ def test_successful_impersonation(self): def test_unsuccessful_impersonation(self): self.assertFailure("myuser", "", "127.0.0.1", "bad-admin-token") + def test_impersonation_with_no_config(self): + with patch.object(config.contest_web_server, "contest_admin_token", None): + self.assertFailure("myuser", "", "127.0.0.1", "admin-token") + def test_impersonation_overrides_unallowed_password_authentication(self): self.contest.allow_password_authentication = False