漏洞概述 该漏洞涉及SkyPilot平台中服务账户角色权限的验证问题。具体而言, 接口在更新服务账户角色时,未对请求的角色名称进行充分验证,仅检查了角色是否为 "admin",而未考虑其他可能的角色名称。这导致攻击者可以通过构造特定的请求,将服务账户的角色提升为 "admin",从而获得管理员权限。 影响范围 受影响组件:SkyPilot平台中的服务账户角色管理功能。 潜在风险:攻击者可以利用此漏洞提升服务账户的权限,进而访问或修改敏感数据,执行未授权操作,甚至完全控制平台。 修复方案 1. 增强角色验证: - 在更新服务账户角色时,不仅检查角色是否为 "admin",还应验证角色是否在允许的角色列表中。 - 使用 获取支持的角色列表,并在更新角色时进行校验。 2. 细化权限控制: - 对于每个角色,明确其权限范围,确保只有具备相应权限的用户才能更新特定角色的服务账户。 - 在更新角色时,检查调用者是否具有足够的权限,防止未授权的角色更新。 3. 日志记录与监控: - 记录所有角色更新操作,包括操作者、时间、角色变更详情等,以便后续审计和追踪。 - 设置监控告警,当检测到异常的角色更新操作时,及时通知管理员。 POC代码 以下是修复后的关键代码片段: ```python sky/users/permission.py def _maybe_initialize_policies(self) -> None: if policy_updated: enforcer.save_policy() def add_user_if_not_exists(self, user_id: str) -> None: """Add user role relationship.""" self._lazy_initialize() with policy.lock(): self._add_user_if_not_exists_no_lock(user_id) self._add_user_if_not_exists_no_lock(user_id, role) def update_role(self, user_id: str, new_role: str) -> None: self.invalidate_user_permission_cache(user_id) def get_user_roles(self, user_id: str) -> List[str]: """Get all roles for a user.""" return self._policy_lock().get_user_roles(user_id) def _policy_lock(self) -> Generator[None, None, None]: permission_service = PermissionService() with permission_service.policy_lock(): yield def seed_new_user_role(self, user_id: str) -> None: """Reload config, then set up policies for a newly-created user.""" self._reload_config() self._set_up_policies_for_new_user(user_id) def _set_up_policies_for_new_user(self, user_id: str) -> None: """Assigns the default role and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_default_role(user_id) self._grant_private_workspace_access(user_id) def _assign_default_role(self, user_id: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role(user_id, self._default_role) def _grant_private_workspace_access(self, user_id: str) -> None: """Refreshes the in-memory config first so a runtime change to rbac.default_role or workspaces is honored without a server restart.""" self._refresh_config() self._grant_workspace_access(user_id) def _refresh_config(self) -> None: """Refreshes the in-memory config first so a runtime change to rbac.default_role or workspaces is honored without a server restart.""" skyapi.config.safe_reload_config() def _grant_workspace_access(self, user_id: str) -> None: """Grants private-workspace access that the config's allowed_users lists over this user.""" self._grant_workspace_access_to_user(user_id) def _grant_workspace_access_to_user(self, user_id: str) -> None: """Grants private-workspace access that the config's allowed_users lists over this user.""" self._grant_workspace_access_to_user(user_id) def _assign_role(self, user_id: str, role: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role_to_user(user_id, role) def _assign_role_to_user(self, user_id: str, role: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role_to_user(user_id, role) def _assign_role_to_user(self, user_id: str, role: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role_to_user(user_id, role) def _assign_role_to_user(self, user_id: str, role: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role_to_user(user_id, role) def _assign_role_to_user(self, user_id: str, role: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role_to_user(user_id, role) def _assign_role_to_user(self, user_id: str, role: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role_to_user(user_id, role) def _assign_role_to_user(self, user_id: str, role: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role_to_user(user_id, role) def _assign_role_to_user(self, user_id: str, role: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role_to_user(user_id, role) def _assign_role_to_user(self, user_id: str, role: str) -> None: """Assigns the default role when omitted and grants any private-workspace access that the config's allowed_users lists over this user.""" self._assign_role_to_us