PII does not disappear when it becomes an embedding

A vector looks like a list of numbers, so teams treat the vector store as anonymized. It is not. The personal data is still in there, and it can be pulled back out.

PII does not disappear when it becomes an embedding

An embedding is a list of floating point numbers. It looks nothing like the text it came from. That resemblance to noise fools a lot of teams into treating the vector store as a safe place to put personal data. The numbers are not a disguise. The person is still in there.

The comforting mistake

Here is the reasoning that goes wrong. We embed the record, the output is a vector, a vector is just math, so the personal data is gone. Feels right. It is exactly backwards.

An embedding is a compression of meaning, and it is built to preserve the information that makes one record different from another. A name, an address, an account number, a medical detail. Those are precisely the things that make a record distinctive, so the embedding holds onto them tightly. That is the whole point of the technique. If embeddings threw away identifying detail, retrieval would not work, because retrieval depends on the vector remembering what the text was actually about.

Two ways the data comes back

Once a vector store holds embeddings of records with personal data, that data is reachable through two doors.

The first is retrieval. That is not an attack, it is the feature working as designed. A user asks a question, the system finds the nearest vectors, pulls the original chunks those vectors point to, and drops them into the model’s context. If the chunk was a support ticket with a customer’s phone number, the phone number is now in the prompt. The vector store almost always keeps the source text alongside the vector so it can return it. The personal data was never removed. It was indexed.

The second door is reconstruction. Research has shown for years that you can approximate the original text from an embedding, especially for short strings like names and identifiers, and even more so if you have any access to the model that produced the vectors. The vector is not a one-way hash. Treating it like one is the error.

Why this bites in production and not the demo

In a pilot, the vector store holds a few hundred hand-picked documents someone already sanitized. In production, an ingestion pipeline embeds whatever flows in: full support histories, uploaded PDFs, database rows, chat logs. Nobody is reading each one first. The embedding step runs automatically, and if the assumption baked into the pipeline is that embedding equals anonymizing, then every piece of PII in the source is now sitting in the vector index, retrievable and reconstructable, with no record that it was ever there.

The failure is quiet. Nothing errors. The feature returns good answers, sometimes with a real person’s private detail included, and the team does not notice because the output looks correct. Fluency hides the leak.

Handle the PII before the vector, not after

The fix is an ordering rule. PII gets handled before the text becomes an embedding, because after that point you have lost your clean chance to do it. A few concrete moves:

  • Detect and mask or drop personal fields in the text before the embedding call, so the vector never encodes what you did not want stored.
  • Decide, per data source, what is allowed into the vector store at all, and keep the sensitive sources behind a boundary.
  • Remember that deleting a user’s data means deleting their vectors and their stored source chunks too, not only the row in the primary database.
  • Treat the vector store as a system that holds personal data, with the same access controls and retention rules as any other store that does.

The mental model to drop is that embedding is a scrubbing step. It is a storage step. What you put in is what you can get back out.

How we approach it at Density Labs

In the AI Opportunity Assessment, our fixed two week, $2,500 engagement, we look at the vector layer as a place personal data accumulates, because it usually is one. We check what gets embedded, whether PII is handled before the embedding call or assumed away by it, and whether a deletion request would actually reach the vectors and the source chunks. Finding this in a diagnosis is cheap. Finding it after a year of ingestion means re-embedding a corpus you can no longer fully account for.

The vector is not a shredder. It is a filing cabinet that looks like noise.