The dashboard is green. Zero findings. And the single richest store of your customers’ data is sitting completely outside the scanner’s field of view.
I’ve watched this movie five times now. Managed data centre to virtualization. Virtualization to cloud. Cloud to containers and microservices. Containers to GenAI. And now, GenAI to autonomous agents. Every transition runs the same plot: the workload sprints ahead, and the tooling that’s supposed to watch it arrives a year or two late, out of breath, insisting everything looks fine.
The last time it bit a team I was advising, the trigger was almost comically boring. Clean CNAPP console, green across the board, and the quarterly posture report went to the board with a satisfying near-zero. What actually flagged the problem was their own external attack-surface tool noticing an open port on a dev subnet nobody remembered owning. Behind it: a Weaviate instance, no auth, answering to the public internet, holding embeddings of three years of customer support tickets.
It took the better part of two days just to find who owned it. The answer was nobody, anymore — a data scientist had stood it up for a retrieval-quality proof-of-concept, pointed it at a copy of real ticket data, shipped the actual feature off a different index, and then left the company. The CSPM never said a word. Not because it failed. Because that risk lives in a place CSPM was never built to look.
// What your scanner actually sees
CSPM reasons about the envelope. The risk is in the contents.
Strip the marketing and a CSPM is a very good graph engine pointed at your cloud control plane. It calls the AWS, Azure and GCP APIs, enumerates resources, reads their config, and reasons about relationships: this security group is open to 0.0.0.0/0, that role can assume this other role, this bucket is public. It’s genuinely excellent at this. It’s why we don’t ship world-readable S3 buckets by accident anymore.
But a vector database sits in one of two blind spots. Managed SaaS like Pinecone isn’t in your cloud account at all — it’s someone else’s tenant, reached over an API key, so the CSPM has zero API surface to enumerate. Self-hosted stores (Milvus, Qdrant, Weaviate, Chroma, pgvector) show only the wrapper: the pod, the service, maybe the volume. The CSPM will tell you the volume is encrypted and the node is patched. It cannot tell you what’s in the index, whether that content is sensitive, or whether the query API in front of it hands the whole thing to anyone who asks.
The vendors admit this if you read past the datasheet. The cleanest framing — it’s Wiz’s own — is that CSPM flags the misconfigured bucket, AI-SPM flags the exposed inference endpoint, and it’s DSPM-for-AI that identifies the PII inside the vector store. Three disciplines, three layers. Most orgs I walk into run exactly one of them.
| Layer / question | CSPM | DSPM for AI | AI-SPM |
|---|---|---|---|
| Is the node patched & the SG closed? | Yes | No | Some |
| Does a Pinecone store even exist? | No | Yes | Yes |
| Is there PII inside the index? | No | Yes | Some |
| Is the query API exposed / unauthenticated? | Maybe | Some | Yes |
| Can these embeddings be inverted to text? | No | No | No |
That bottom row is the one nobody owns yet — hold that thought.
// The core misconception
An embedding is not a hash.
Here’s the belief I have to dismantle in almost every review, held by smart people: “The vectors are just floats. They’re anonymized. Even if someone grabbed them, there’s nothing to read.”
This is the single most expensive misunderstanding in AI infrastructure right now, and it’s a bad analogy. Engineers pattern-match “irreversible numerical transform” onto hash, and hashes really are one-way. An embedding is the opposite thing. Its entire job is to preserve as much source meaning as possible in a compact numerical form — a lossy compression of semantics, and lossy compression is, by definition, partially decompressible.
The research settled this and keeps getting worse for defenders. Vec2Text (Morris et al., 2023) framed inversion as controlled generation and reconstructs a meaningful chunk of the source, black-box, with no access to the original model’s weights. Independent write-ups put practical recovery at roughly 60–80% of the content of typical corporate documents from mainstream models like ada-002, BGE and Cohere Embed. On the MIMIC-III clinical notes, researchers reconstructed full patient names. And the defenses age badly: adding Gaussian noise trades directly against retrieval quality, and newer zero-shot methods are explicitly robust to it. Assume any embedding of sensitive text is the sensitive text.
A healthcare-adjacent client walked me through their “privacy-preserving” RAG design with real pride. The pitch: they never stored source clinical text anywhere, only embeddings, so the vector DB was out of scope for their data-protection controls. “It’s just math,” the lead engineer said.
We ran an open inversion model against a handful of their ada-002 vectors, in the room, on a laptop. It came back with recognizable fragments of clinical narrative, names included. The meeting got very quiet. The store went back in scope that afternoon. “It’s just math” is precisely how the math gets you.
A vector-store breach isn’t a metadata leak. If the embeddings can be inverted, it’s a plaintext document breach.
// Where it actually breaks
Four failure modes your posture report will never show you.
Inversion is why the stakes are high. These are the four ways I actually watch data leave the building — and none of them generate a CSPM finding.
These are young databases, and many ship auth-off-by-default. Internet scans have surfaced thousands of exposed instances. The CVEs are ugly: Milvus CVE-2025-64513 (CVSS 9.3) let an attacker forge one HTTP header for full admin; Weaviate’s CVE-2024-31621 was an auth bypass triggered by sending the path in the wrong case. Orca’s team found an exposed store indexing support tickets — with plaintext customer credentials pasted into them.
Most stores do multi-tenancy by attaching a tenant_id to each vector and filtering at query time. That’s application-level scoping, not row-level security — there’s no database-enforced boundary underneath. One injection, one refactor that drops the clause, one bug in the retrieval layer, and cross-tenant results flow.
We obsess over read exposure and ignore writes. Keys are frequently minted with full read and write scope across the whole cluster. An attacker who gets one — or who can slip a document into your ingestion source — poisons the corpus, an integrity attack on every answer your RAG system gives. CSPM has no concept of corpus integrity at all.
Sensitivity has to travel with the data as it flows S3 → chunker → embedding API → store — exactly what DSPM lineage does and nothing else does. Most deployments log nothing about queries, so slow bulk-exfiltration via similarity search runs for months. And don’t dump raw vectors into your logs: a line reading query_vector:[0.12,0.45,...] is invertible. You just moved the sensitive data into Splunk.
// Who owns this?
The vector store’s real vulnerability is that nobody owns it.
Every one of these technical gaps rode in on an organizational one. The vector DB gets stood up by the ML or data team, who are measured on retrieval quality and shipping the feature — not on posture. Security doesn’t know it exists because it never crossed a review gate. Platform doesn’t treat it as a database because it doesn’t look like one: no schema, no DBA, no line on the CMDB. So it lives in the seam between three teams, and the seams are where I’ve found nearly every serious problem of my career.
The pattern I hit most is the POC leak: someone copies real production data into a dev vector DB to benchmark answer quality, the feature ships from a proper index, and the dev store with real customer data sits there for months — production PII, dev-account blast radius, monitored by no one. And the way I actually find shadow RAG isn’t a scanner — it’s the embedding-API bill. A line item for a few million text-embedding-3 calls that no one in security has heard of is a vector store you don’t know about yet. Follow the money to the data.
// Why the old muscle memory fails
The controls you trust don’t transfer cleanly.
DLP and classification break on float arrays. Your regex-and-dictionary DLP is hunting for things that look like SSNs and card numbers. A 1,536-dimension vector matches none of its patterns, so it sails through — even though it may encode an entire paragraph of regulated text.
Encryption-at-rest is real, and also theater here. Encrypt the volume — you should. But approximate-nearest-neighbor search operates on the plaintext vectors; the index holds usable vectors in memory to do its job. The exposure isn’t the disk, it’s the live query surface and process memory.
And the regulators haven’t caught up. Whether an embedding of personal data is personal data under GDPR or HIPAA is genuinely unsettled. Given the inversion research, treat it as the regulated text and let the lawyers catch up to you, not the reverse.
// What I actually do about it
The hands-on playbook, minus the vendor pitch.
Tools follow ownership and a threat model — never lead. Here’s the order I work in, and the config I actually ship.
1 · Find them for real
You can’t protect what your primary scanner refuses to enumerate. Hunt the shadow ones the way an attacker would — plus two moves an attacker can’t make: read your own IaC, and read the embedding bill.
# 1. The attacker's view — probe the default ports. curl http://<host>:8080/v1/schema # Weaviate curl http://<host>:19530/v2/vectordb/collections/list # Milvus curl http://<host>:8000/api/v1/collections # Chroma # 2. The move an attacker can't make — grep your own IaC. grep -rEi 'pinecone|weaviate|qdrant|milvus|chroma|pgvector' ./infra/ # 3. Follow the money — unknown embedding spend = unknown store. # Check the OpenAI / Cohere / Bedrock usage export.
2 · Classify at the level of the source corpus
No exceptions. If the pipeline indexed support tickets, clinical notes, or contracts, then the store is a support-ticket / PHI / contract store. The embedding step doesn’t launder the classification.
3 · Split the keys by blast radius
Pinecone now has real RBAC — six API-key roles, three control-plane and three data-plane. The pipeline that writes should not be able to read the index back, and the app that reads should never write. Manage it in IaC so it’s reviewable.
# Two keys, two blast radii. resource "pinecone_api_key" "ingest" { roles = ["DataPlaneEditor"] # upsert only, no read } resource "pinecone_api_key" "query" { roles = ["DataPlaneViewer"] # read only, no write } # Neither key carries a control-plane role.
4 · Make tenant isolation a boundary, not a hope
This is the decision that matters most, and it’s a real fork.
The one option that gives you what pure vector stores don’t: a boundary the database enforces, not the app. A dropped WHERE clause simply cannot leak across tenants, because Postgres refuses the rows. My default for anything multi-tenant and sensitive.
Physical separation in a dedicated vector store. Strong, but it costs money and creates index sprawl at high tenant counts. I reserve it for the highest-sensitivity tenants rather than applying it uniformly.
The default, and the weakest. If you must, the tenant filter cannot be the only control and absolutely cannot be a client-supplied value.
-- pgvector rides in Postgres: real, DB-enforced isolation. ALTER TABLE doc_chunks ENABLE ROW LEVEL SECURITY; ALTER TABLE doc_chunks FORCE ROW LEVEL SECURITY; -- even the owner CREATE POLICY tenant_isolation ON doc_chunks USING (tenant_id = current_setting('app.tenant_id')::uuid); -- A forgotten WHERE clause now cannot leak across tenants.
5 · Scrub before you embed
You can delete a row. You cannot un-embed a leaked meaning. Redact secrets and needless PII in preprocessing, before the text ever becomes a vector — and be honest that NER-based redaction is good, not perfect, and costs you some recall. Budget that recall hit on purpose.
6 · Log the data plane
Managed stores mostly emit audit logs now — ship them to your SIEM. Self-hosted usually gives you nothing, so front the store with a proxy that logs every query and upsert. Alert on the shape of exfiltration: unusually high top_k, one key issuing many distinct queries fast, or retrieval volume far above a key’s baseline. Never log raw vectors.
If a vector store leaks, key rotation limits future access — it does nothing about what already walked out the door. And because the embeddings are invertible, you cannot treat the exposure as “just vectors.” For breach-notification purposes, assume disclosure of the source text those vectors encode.
That means the questions you’ll be asked at 2 a.m. — what data was in that index, whose was it, and can you prove the scope? — need answers you built before the incident: source-corpus classification, ingestion lineage, and query logs. Retrofitting them mid-incident is how a contained problem becomes a disclosure event.
// How I’d sequence it
You won’t get all of this on day one. Do it in this order.
Days 0–30 — see it and close the front door. Find every store, put them on the inventory with a named owner, classify each at its source-corpus level, then kill public exposure, turn on auth, patch past the known CVEs, and shut down forgotten POC stores. None of this touches retrieval quality, so none of it triggers the fight.
Days 30–90 — scope, isolate, and watch. Split read/write keys, make the tenant-isolation call, add ingestion redaction (this is where you negotiate the recall budget with data science, metric in hand), and stand up query logging with bulk-retrieval alerting.
Day 90+ — authorize and govern. Add per-document authorization for RAG, wire the stores into DSPM-for-AI / AI-SPM tooling, and bake a vector-store checklist into the design-review gate so the next POC can’t skip it.
// The throughline
Trust the workload, not the green dashboard.
Every time the industry adopts a new place to put data, that place shows up in production a year or two before our tooling learns to see it — and for that gap, the only thing between the data and the internet is whether a human bothered to reason about it directly. Data centre, virtualization, cloud, containers, GenAI: the same gap every time, only the coordinates change.
And the coordinates are moving again. Autonomous agents now read and write these stores on their own, at machine speed, under their own service identities, chaining a retrieval straight into an action with no human in the loop. Every un-owned, un-logged, un-scoped vector store you have is about to get queried thousands of times an hour by something that doesn’t read the dashboard either. The blind spot doesn’t shrink in the agentic era. It gets hammered.
Your CSPM isn’t broken. It just was never designed to look here. The mistake isn’t trusting the tool — it’s trusting the silence, reading a clean report as “we’re safe” instead of “the scanner had nothing to say about the things it can see.” Go find yours. Check the embedding bill, not the dashboard.
- ✓Owned — every store has a named owner and a line on the inventory; shadow and POC stores hunted down.
- ✓Classified — each store carries the sensitivity of the corpus it was built from.
- ✓Closed — no public exposure, auth enforced, patched past the known auth-bypass CVEs.
- ✓Scoped — read/write keys split via RBAC, least privilege, rotated.
- ✓Isolated — tenant separation enforced below the app (RLS or physical), never a client filter.
- ✓Scrubbed — secrets and needless PII stripped before embedding.
- ✓Observed — queries and writes logged, bulk-retrieval alerting on, raw vectors never logged.
- ✓IR-ready — classification, lineage, and logs exist before the incident, so you can prove scope at 2 a.m.
Written by a principal security architect with roughly 18 years across fintech, SaaS, and consulting — through every platform shift from the managed data centre to virtualization, cloud, containers, GenAI, and now agentic AI. Views are the author’s own and don’t constitute legal, regulatory, or financial advice. Client scenarios here are composites, anonymized and lightly fictionalized to make a real pattern legible; any resemblance to a specific organization is coincidental. Treat vendor capabilities and config snippets as starting points for your own testing, not guarantees — API names and roles change.
Found your blind spot?
Send this to whoever owns your RAG stack.
The best time to inventory your vector stores was before the agents started querying them. The second-best time is now.
