Browse Source

[ENG-5784] Restrict `update_vars_internal` to browser storage vars (#5293)

Only allow reflex API event `update_vars_internal` to update vars associated
with client storage values.

[CVE-2025-47425]
[GHSA-rf8x-9mhr-49wg]
Masen Furer 4 days ago
parent
commit
cf8f5dbcbd
1 changed files with 27 additions and 6 deletions
  1. 27 6
      reflex/state.py

+ 27 - 6
reflex/state.py

@@ -1402,6 +1402,29 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
         for substate in self.substates.values():
             substate.reset()
 
+    @classmethod
+    @functools.lru_cache
+    def _is_client_storage(cls, prop_name_or_field: str | ModelField) -> bool:
+        """Check if the var is a client storage var.
+
+        Args:
+            prop_name_or_field: The name of the var or the field itself.
+
+        Returns:
+            Whether the var is a client storage var.
+        """
+        if isinstance(prop_name_or_field, str):
+            field = cls.get_fields().get(prop_name_or_field)
+        else:
+            field = prop_name_or_field
+        return field is not None and (
+            isinstance(field.default, ClientStorageBase)
+            or (
+                isinstance(field.type_, type)
+                and issubclass(field.type_, ClientStorageBase)
+            )
+        )
+
     def _reset_client_storage(self):
         """Reset client storage base vars to their default values."""
         # Client-side storage is reset during hydrate so that clearing cookies
@@ -1409,10 +1432,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
         fields = self.get_fields()
         for prop_name in self.base_vars:
             field = fields[prop_name]
-            if isinstance(field.default, ClientStorageBase) or (
-                isinstance(field.type_, type)
-                and issubclass(field.type_, ClientStorageBase)
-            ):
+            if self._is_client_storage(field):
                 setattr(self, prop_name, copy.deepcopy(field.default))
 
         # Recursively reset the substate client storage.
@@ -2393,8 +2413,9 @@ class UpdateVarsInternalState(State):
         for var, value in vars.items():
             state_name, _, var_name = var.rpartition(".")
             var_state_cls = State.get_class_substate(state_name)
-            var_state = await self.get_state(var_state_cls)
-            setattr(var_state, var_name, value)
+            if var_state_cls._is_client_storage(var_name):
+                var_state = await self.get_state(var_state_cls)
+                setattr(var_state, var_name, value)
 
 
 class OnLoadInternalState(State):