diff --git a/core/auth.py b/core/auth.py index 9dfa0431c..8ea1cfac0 100644 --- a/core/auth.py +++ b/core/auth.py @@ -396,6 +396,15 @@ class AuthManager: current = self.get_privileges(username) for k, v in privileges.items(): if k in DEFAULT_PRIVILEGES: + default = DEFAULT_PRIVILEGES[k] + if isinstance(default, bool): + ok = isinstance(v, bool) + elif isinstance(default, int): + ok = isinstance(v, int) and not isinstance(v, bool) + else: + ok = isinstance(v, list) + if not ok: + raise ValueError(f"Invalid value for privilege '{k}'") current[k] = v self._config["users"][username]["privileges"] = current self._save() diff --git a/routes/auth_routes.py b/routes/auth_routes.py index fc47719b7..a86e1ca35 100644 --- a/routes/auth_routes.py +++ b/routes/auth_routes.py @@ -362,8 +362,16 @@ def setup_auth_routes(auth_manager: AuthManager) -> APIRouter: user = _get_current_user(request) if not user or not auth_manager.is_admin(user): raise HTTPException(403, "Admin only") - body = await request.json() - ok = auth_manager.set_privileges(username, body) + try: + body = await request.json() + except ValueError: + raise HTTPException(400, "Request body must be a JSON object") + if not isinstance(body, dict): + raise HTTPException(400, "Request body must be a JSON object") + try: + ok = auth_manager.set_privileges(username, body) + except ValueError as e: + raise HTTPException(400, str(e)) if not ok: raise HTTPException(404, "User not found or is admin") return {"ok": True, "privileges": auth_manager.get_privileges(username)} diff --git a/tests/test_set_privileges_validation.py b/tests/test_set_privileges_validation.py new file mode 100644 index 000000000..fc02a9ad4 --- /dev/null +++ b/tests/test_set_privileges_validation.py @@ -0,0 +1,42 @@ +"""set_privileges rejects mistyped values instead of storing them (issue #6829).""" + +import pytest + +from tests.test_set_admin import _fresh_auth_manager + + +@pytest.mark.parametrize("privs", [ + {"can_use_bash": "no"}, + {"can_use_bash": 1}, + {"max_messages_per_day": "abc"}, + {"max_messages_per_day": True}, + {"allowed_models": "gpt"}, + {"block_all_models": None}, +]) +def test_set_privileges_rejects_mistyped_values(tmp_path, privs): + _, mgr = _fresh_auth_manager(tmp_path) + mgr.create_user("bob", "pw-123456") + before = dict(mgr.get_privileges("bob")) + + with pytest.raises(ValueError): + mgr.set_privileges("bob", privs) + + assert mgr.get_privileges("bob") == before + + +def test_set_privileges_accepts_well_typed_values(tmp_path): + _, mgr = _fresh_auth_manager(tmp_path) + mgr.create_user("bob", "pw-123456") + + assert mgr.set_privileges("bob", { + "can_use_bash": True, + "max_messages_per_day": 25, + "allowed_models": ["gpt"], + "unknown_key": "ignored", + }) is True + + privs = mgr.get_privileges("bob") + assert privs["can_use_bash"] is True + assert privs["max_messages_per_day"] == 25 + assert privs["allowed_models"] == ["gpt"] + assert "unknown_key" not in privs