From e1ea82d7cf4ff933fee2abd6cafbd7ac4a1946c0 Mon Sep 17 00:00:00 2001 From: Dmitry Maranik Date: Tue, 16 Jun 2026 15:58:30 -0700 Subject: [PATCH] fix(connectors): scope index endpoint authorization to the connector's own search space The POST /search-source-connectors/{connector_id}/index endpoint loaded the connector by id and then called check_permission() against the client-supplied search_space_id query parameter (the caller's own space) rather than the connector's own search_space_id, and never verified that the two matched. A user could therefore index another user's connector by passing their own search_space_id: the indexer ran with the victim connector's stored credentials and wrote the fetched content into the attacker's search space. The read/update/delete handlers already authorize against connector.search_space_id; this brings the index handler in line. Reject a connector that does not belong to the requested search space (404, to avoid disclosing connectors in other spaces) and authorize the permission check against connector.search_space_id. --- .../routes/search_source_connectors_routes.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/surfsense_backend/app/routes/search_source_connectors_routes.py b/surfsense_backend/app/routes/search_source_connectors_routes.py index dc26b4c02..512b52ae4 100644 --- a/surfsense_backend/app/routes/search_source_connectors_routes.py +++ b/surfsense_backend/app/routes/search_source_connectors_routes.py @@ -745,11 +745,23 @@ async def index_connector_content( if not connector: raise HTTPException(status_code=404, detail="Connector not found") - # Check if user has permission to update connectors (indexing is an update operation) + # Ensure the connector actually belongs to the requested search space. + # Without this, the permission check below would authorize against the + # caller-supplied search_space_id (their own space) while the connector + # lives in another user's space, allowing cross-tenant indexing of a + # foreign connector (and use of its stored credentials). Returning 404 + # (rather than 403) on a mismatch also avoids disclosing the existence of + # connectors in other search spaces. + if connector.search_space_id != search_space_id: + raise HTTPException(status_code=404, detail="Connector not found") + + # Check if user has permission to update connectors (indexing is an update + # operation). Authorize against the connector's OWN search space — matching + # the read/update/delete handlers — not the client-supplied query param. await check_permission( session, user, - search_space_id, + connector.search_space_id, Permission.CONNECTORS_UPDATE.value, "You don't have permission to index content in this search space", )