From 990e8feee8ea4987b3286cc80711dbf0202f4301 Mon Sep 17 00:00:00 2001 From: GareArc Date: Mon, 26 Jan 2026 16:00:43 -0800 Subject: [PATCH] security: fix IDOR and privilege escalation in set_default_provider - Add tenant_id verification to prevent IDOR attacks - Add admin check for enterprise tenant-wide default changes - Preserve non-enterprise behavior (users can set own defaults) --- api/controllers/console/workspace/tool_providers.py | 6 +++++- api/services/tools/builtin_tools_manage_service.py | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/api/controllers/console/workspace/tool_providers.py b/api/controllers/console/workspace/tool_providers.py index 5bfa895849..f5de6709dd 100644 --- a/api/controllers/console/workspace/tool_providers.py +++ b/api/controllers/console/workspace/tool_providers.py @@ -878,7 +878,11 @@ class ToolBuiltinProviderSetDefaultApi(Resource): current_user, current_tenant_id = current_account_with_tenant() payload = BuiltinProviderDefaultCredentialPayload.model_validate(console_ns.payload or {}) return BuiltinToolManageService.set_default_provider( - tenant_id=current_tenant_id, user_id=current_user.id, provider=provider, id=payload.id + tenant_id=current_tenant_id, + user_id=current_user.id, + provider=provider, + id=args["id"], + account=current_user, ) diff --git a/api/services/tools/builtin_tools_manage_service.py b/api/services/tools/builtin_tools_manage_service.py index 7afbae92b0..667cde3d48 100644 --- a/api/services/tools/builtin_tools_manage_service.py +++ b/api/services/tools/builtin_tools_manage_service.py @@ -406,18 +406,23 @@ class BuiltinToolManageService: return {"result": "success"} @staticmethod - def set_default_provider(tenant_id: str, user_id: str, provider: str, id: str): + def set_default_provider(tenant_id: str, user_id: str, provider: str, id: str, account: "Account | None" = None): """ set default provider """ with Session(db.engine) as session: - # get provider - target_provider = session.query(BuiltinToolProvider).filter_by(id=id).first() + # get provider (verify tenant ownership to prevent IDOR) + target_provider = session.query(BuiltinToolProvider).filter_by(id=id, tenant_id=tenant_id).first() if target_provider is None: raise ValueError("provider not found") # clear default provider if dify_config.ENTERPRISE_ENABLED: + # Enterprise: verify admin permission for tenant-wide operation + from models.account import TenantAccountRole + + if account and not TenantAccountRole.is_privileged_role(account.current_role): + raise ValueError("Only workspace admins/owners can set default credentials in enterprise mode") # Enterprise: clear ALL defaults for this provider in the tenant # (regardless of user_id, since enterprise credentials may have different user_id) session.query(BuiltinToolProvider).filter_by(