From 707efeaed7992dd9896d5928559458f228b9a539 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 27 Jul 2026 08:18:38 +0200 Subject: [PATCH] fix: scope knowledge sync cleanup deletions to the target knowledge base (#26722) POST /knowledge/{id}/sync/cleanup verified write access to the knowledge base in the URL but then acted on the caller-supplied file_ids and dir_ids without checking they belong to that knowledge base. A user with write access to any knowledge base could pass another knowledge base's directory id to delete its directory subtree and knowledge_file associations, or another file's id to drop its file-{file_id} vector collection. Fetch each directory and skip any whose knowledge_id does not match the URL id (matching the explicit directory-delete endpoint), and gate the per-file vector cleanup on Knowledges.has_file(id, file_id) so a foreign file id cannot trigger collection deletion. Legitimate same-knowledge-base cleanup is unchanged. Co-authored-by: whyiug --- backend/open_webui/routers/knowledge.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index b80e448149..cd98681efd 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -1943,6 +1943,10 @@ async def sync_knowledge_cleanup( if not file: continue + # Only clean up files that belong to this knowledge base. + if not await Knowledges.has_file(id, file_id, db=db): + continue + await Knowledges.remove_file_from_knowledge_by_id(id, file_id, db=db) try: @@ -1967,6 +1971,10 @@ async def sync_knowledge_cleanup( # ── Remove orphaned directories (children before parents) ── for dir_id in reversed(form_data.dir_ids): + # Only delete directories that belong to this knowledge base. + directory = await Knowledges.get_directory_by_id(dir_id, db=db) + if not directory or directory.knowledge_id != id: + continue await Knowledges.delete_directory(dir_id, move_files_to_parent=False, db=db) return {'status': True}