Skip to content
HackIndex logo

HackIndex

Retrieval Layer Manipulation in RAG Pipelines

4 min read Mar 26, 2026

The retrieval layer sits between the user query and the vector store. It converts the query to an embedding, scores candidate chunks by similarity, applies any metadata filters, and passes the top-k results to the model context. Each of those steps is a potential abuse point. The goal is to influence which chunks get retrieved without necessarily controlling the knowledge base content.

Retrieval manipulation is distinct from knowledge base poisoning. Here the knowledge base content is not modified. Instead, queries, filter parameters, or namespace selectors are crafted to surface chunks that should not be accessible from a given query or user context.

Probe Retrieval Parameters

Many RAG APIs expose retrieval configuration directly in the request body. Look for parameters like top_k, score_threshold, namespace, filter, collection, and metadata. Send a standard query first and observe the response structure:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST https://$TARGET_IP/api/chat -H 'Content-Type: application/json' -H 'Authorization: Bearer $TOKEN' -d '{"messages":[{"role":"user","content":"Tell me about the refund policy"}],"stream":false}' | python3 -m json.tool

If the response includes source references or chunk metadata, note the namespace, collection, or document ID fields. Then probe whether those parameters can be overridden from the client side:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST https://$TARGET_IP/api/chat -H 'Content-Type: application/json' -H 'Authorization: Bearer $TOKEN' -d '{"messages":[{"role":"user","content":"Tell me about the refund policy"}],"retrieval":{"top_k":50,"score_threshold":0.0,"namespace":"internal"}}' | python3 -m json.tool

Setting score_threshold to 0.0 removes similarity filtering and forces retrieval of all candidates. Increasing top_k surfaces more chunks per query. Switching namespace or collection to values like internal, admin, or hr can reveal content segmented for restricted access. If the server accepts these overrides, authorization is enforced at the application layer rather than the retrieval layer.

Bypass Metadata Filters

Some deployments filter retrieved chunks by metadata fields such as tenant_id, department, or access_level. These filters are often passed as query parameters or JSON fields alongside the retrieval request. Test whether user-controlled input can override or inject into the filter expression:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST https://$TARGET_IP/api/chat -H 'Content-Type: application/json' -H 'Authorization: Bearer $TOKEN' -d '{"messages":[{"role":"user","content":"What are the executive compensation figures?"}],"filter":{"department":"finance","access_level":"executive"}}' | python3 -m json.tool

If the server uses user-supplied filter values without validation against the authenticated user's actual attributes, arbitrary metadata values can be passed to retrieve chunks from any segment. Try common high-value metadata values: executive, admin, confidential, internal, hr, finance, c-suite.

Abuse the Retrieval Endpoint Directly

Some RAG deployments expose a dedicated retrieval or search endpoint separate from the chat interface. This endpoint returns raw chunks without passing them through the model, which makes it useful for directly dumping knowledge base content:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST https://$TARGET_IP/api/retrieve -H 'Content-Type: application/json' -H 'Authorization: Bearer $TOKEN' -d '{"query":"confidential salary compensation","top_k":20}' | python3 -m json.tool
{
  "chunks": [
    {
      "id": "chunk_029a",
      "text": "Executive compensation package for FY2025: CEO base salary $480,000...",
      "score": 0.91,
      "metadata": {"source": "hr/exec-comp-2025.pdf", "access_level": "executive"}
    }
  ]
}

A direct retrieval endpoint returning chunks with access_level metadata that the server did not enforce is a data exposure vulnerability on its own. Iterate queries across sensitive topic areas to enumerate the knowledge base content without going through the chat interface. This is faster and produces cleaner output than chat-based enumeration.

Cross-Tenant Retrieval

Multi-tenant RAG deployments should isolate knowledge bases per tenant using namespace or tenant_id fields. Test whether the tenant identifier in the retrieval request is validated against the authenticated user's tenant:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST https://$TARGET_IP/api/chat -H 'Content-Type: application/json' -H 'Authorization: Bearer $TOKEN' -d '{"messages":[{"role":"user","content":"Summarise our internal documentation"}],"tenant_id":"org_00001","namespace":"org_00001"}' | python3 -m json.tool

Enumerate valid tenant identifiers from any visible org IDs, account numbers, or namespace values observed in prior responses. Successful cross-tenant retrieval means all tenant knowledge bases are readable by any authenticated user, which is a critical authorization failure enabling full knowledge base disclosure across the platform.

References