Gate outside writes on the owner's stored credentials, not only connections

API-key, widget and public-link callers were held to the write allowlist
only on connected accounts, so they could still write through an API
tool or a signed-in MCP server that carries the owner's credentials. Any
write on credentials the caller doesn't hold is now refused unless the
owner allowlisted it, and a scheduled run for such a caller counts as not
holding any. The tool list names these writes per tool, so the allowlist
can offer them, and its copy now names every route it covers.
This commit is contained in:
arc53-machine committed 2026-09-29 15:41:34 +01:00
1 parent 656e3abbd0
commit 5c8b97b609
14 files changed
+243 -36

No files matched your search

+4
View File
@@ -36,6 +36,7 @@ from docsgpt.api.user.resource_access import (
from docsgpt.api.user.team_sharing import visible_with_access
from docsgpt.connectors.catalog import base_url, definition_for_tool
from docsgpt.connectors.service import account_tool_names
from docsgpt.connectors.permissions import owner_credential_writes
from docsgpt.core.settings import settings
from docsgpt.core.url_validation import SSRFError, validate_url
from docsgpt.security.encryption import CredentialDecryptionError, decrypt_credentials, encrypt_credentials
@@ -709,6 +710,9 @@ class GetTools(Resource):
def _shape_tool(row, *, ownership="user", force_strip_secret=False):
tool_copy = _row_to_api(row)
# The writes an agent's API write allowlist can cover (read
# from the stored row, before any secret is masked).
tool_copy["owner_credential_writes"] = owner_credential_writes(row)
config_req = tool_copy.get("configRequirements", {})
if not config_req:
tool_instance = tool_manager.tools.get(tool_copy.get("name"))