DEV Community

Srivatsa Kamballa
Srivatsa Kamballa

Posted on

Leaked embeddings are leaked text: the RAG risk nobody checks

Most RAG security talk is about prompt injection. Here's a risk almost nobody checks: the embedding vectors themselves.

Embeddings are not a one-way hash

It's tempting to treat an embedding as a safe, anonymized fingerprint of your text. It isn't. Recent work (vec2text, Morris et al., 2023) showed you can invert an embedding back into much of its original text. The attack is simple in spirit: start from a guess, embed it, compare to the target vector, and iteratively edit the text until its embedding matches. Given the vector, the decoder reconstructs a large chunk of what you embedded, often near verbatim for short passages.

So an embedding is as sensitive as the source document it encodes. If your pipeline hands out raw vectors anywhere, it is leaking the content those vectors came from, even if the text never leaves the box.

What the leak actually looks like

The dangerous part is that it never looks like a breach. Here's a "helpful" debug response from a RAG API:

{
  "answer": "Our refund window is 30 days.",
  "debug": {
    "retrieved_chunks": [
      {
        "source": "internal/refund-policy.md",
        "embedding": [0.0123, -0.0917, 0.0442, 0.1131, -0.0075, 0.0881, -0.0210, 0.0559]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

There's no obvious secret there, just a list of floats. But that embedding array can be inverted back into the chunk it came from. If that chunk was private, you just shipped it to the client in a field nobody thought to guard.

RAG pipelines expose vectors in more places than you'd think:

  • A debug or verbose mode that includes the embedding in the response
  • Logs that dump the query or chunk vector while troubleshooting
  • API metadata that returns the vector alongside the answer
  • A vector store or admin endpoint with weak access control

The fix is boring and effective

  • Never return raw embeddings to clients. Strip them from responses and debug output.
  • Keep vectors out of logs. Log an ID or a hash, not the vector.
  • Treat your vector store like a datastore full of sensitive text, because that is what it is. Access-control it.
  • Access-control any debug endpoint that can surface vectors.

How to check your own pipeline

The zero-effort version: grep your logs and captured API responses for long runs of floats.

grep -RnE '\[-?[0-9]+\.[0-9]+(, *-?[0-9]+\.[0-9]+){7,}' ./logs
Enter fullscreen mode Exit fullscreen mode

If that finds anything a user or an attacker could reach, treat it like you found a password in there. Because functionally, you did.

I added a probe for exactly this to rag-redteam in v0.3. It asks a pipeline for its vectors a few different ways and flags any response that actually contains a raw embedding. It's one of seven probes that test the retrieval pipeline itself, not the model, for injection and leakage, and it runs as a CI gate:

pip install rag-redteam
rag-redteam run --target mypackage.my_rag:build --probes embedding_inversion
Enter fullscreen mode Exit fullscreen mode

Repo and threat model: https://github.com/Srivatsa03/rag-redteam

Prompt injection gets all the attention, but your embeddings are quietly carrying the same text you were trying to protect. Check where they end up.

Top comments (6)

Collapse
 
kartik-nvjk profile image
Kartik N V J K

The vec2text result is the part people underrate, because most teams treat the vector store as if it were a one-way hash and never threat-model it as plaintext. What made it click for me was realizing an embedding keeps enough semantic structure to reconstruct names and phrasing, so PII in the source survives the encoding. Have you seen the inversion quality hold up on domain-specific embeddings, or does it degrade once the model is fine-tuned away from the public checkpoint?

Collapse
 
srivatsa_kamballa profile image
Srivatsa Kamballa • Edited

Honestly, I haven't measured that. My probe only checks whether a pipeline hands the vector out at all, not how well it inverts, so I've got exposure data and nothing on reconstruction quality.

My guess, and it is a guess: inversion probably does degrade the further you fine-tune, since vec2text-style attacks train a corrector against one encoder's geometry. Move the encoder and you've broken the attacker's model, not the leak itself. That's a cost increase rather than a defense though. The information is still sitting in the vector, and anyone who can hit your embedding endpoint can generate pairs and retrain.

What would actually answer it: same corpus, one public checkpoint against that model fine-tuned at a few different step budgets, then measure reconstruction quality against how far you've drifted from the base weights. If nobody's run that yet it'd make a fun weekend.

Collapse
 
topstar_ai profile image
Luis Cruz

Excellent point. Many teams treat embeddings as “safe because they are not raw text,” but that assumption can create a false sense of security.

Embeddings are not just random vectors — they are compressed representations of information. Depending on the model, data sensitivity, and attack method, they can reveal more than teams expect.

For production RAG systems, security needs to exist across the entire pipeline:

Access control before retrieval, not only after generation
Tenant isolation for vector databases
Encryption and strict permissions for embedding storage
Metadata filtering with authorization checks
Monitoring unusual retrieval patterns
Careful handling of document chunking and context exposure

Another important aspect is that RAG security is not only about preventing prompt injection. The retrieval layer itself becomes a data access layer, and it needs the same security principles as traditional databases.

The right mental model is:

A vector database is not a cache of harmless AI context — it is a knowledge store with security requirements.

As AI applications move into enterprise environments, privacy, governance, and retrieval authorization will become just as important as model quality.

Great discussion. RAG security deserves much more attention. 👏

Collapse
 
srivatsa_kamballa profile image
Srivatsa Kamballa • Edited

The "retrieval layer is a data access layer" line is the bit I'd keep. That's really why RAG authorization is usually broken. Teams put ACLs on the document store, then embed everything into one shared index and let the retriever walk straight across every boundary those ACLs drew. The vector store inherits none of the permissions of whatever it ingested from, and hardly anyone re-checks entitlement at retrieval time.

Good news is that one's a lot cheaper to fix than inversion. Filter by principal at query time instead of hoping top-k just happens not to surface someone else's chunk.

Collapse
 
vinimabreu profile image
Vinicius Pereira

Adding to the "treat it as a plaintext datastore" thread: encryption at rest is almost orthogonal to the leak you named. A debug response and a log line are data in use and egress, not data at rest, so a perfectly encrypted vector store still hands every embedding to whoever reads the verbose response or the APM trace. The control that closes your surface is output hygiene, strip vectors from responses and never log raw floats, which is a different job than the DB encryption people reach for first.

And stripping the floats is necessary but not sufficient: the similarity API is itself a slow inversion oracle. An attacker who cannot see the vector but can submit probe text and read back a nearest-neighbor distance can run the same iterative guessing against the score. So the retrieve endpoint leaks what you removed from the response, just slower, and is worth threat-modeling as a reconstruction channel, not only the debug field. Small kicker: vec2text is sharpest on short passages, so the tight chunks everyone tunes for retrieval quality are also the most invertible.

Collapse
 
srivatsa_kamballa profile image
Srivatsa Kamballa

Yeah, you got me on the score oracle. My probe just asks the pipeline for its vectors a few different ways and flags anything that comes back looking like a run of floats. So it catches the output-hygiene channel and completely misses an endpoint that only ever hands back a distance. Same leak, slower timer.

The chunk-size thing is the one that actually bugs me. Everyone tunes toward small tight chunks because that's what retrieval quality wants, and that's exactly the regime where inversion is sharpest. So you get punished for doing retrieval well. Best I've got is truncating score precision and rate limiting the probe loop, and neither of those is a fix, they just make it tedious for the attacker.

Adding the score-oracle probe. Nastier test than the one I shipped.