All field notes
Data Substrates8 min read15 Jul 2026

Vector Access Control Leaks: Why Post-Retrieval Filtering is a Security Lie

An agent that can be talked into querying your database is only as contained as the credentials you handed it. How embedding inversion attacks leak raw data, and why RBAC must be enforced at the storage engine level.

Logic42 Data Practice

Access control designed for humans assumes the attacker cannot see the query interface. Agents invalidate that assumption.

A person using an internal enterprise application is constrained by the UI screens built for them. They see specific fields, filter what the search dropdown permits, and the backend application controls which rows to fetch. Decades of enterprise security quietly depend on this paradigm: coarse role-based access control (RBAC) at the application layer because the application controls the questions.

An autonomous AI agent has no screens. It composes queries directly, at machine speed, across whatever database interfaces its credentials reach. And unlike a person, it can be persuaded—by hidden text in a PDF, a comment in a support ticket, or an injected prompt—to execute queries nobody intended.

The exfiltration path is not the text prompt; it is the data retrieval payload.

This article analyzes where retrieval-based access control leaks in vector and relational systems, and how to build a zero-trust data substrate that holds under adversarial conditions.


1. The Post-Retrieval Filtering Lie

The most common architectural defect in RAG (Retrieval-Augmented Generation) applications is post-retrieval filtering.

In this naive pattern, the application queries the vector database for top-k similar documents, receives 20 chunks from the index, and then checks whether the requesting user is allowed to read those documents.

❌ WRONG (Post-Retrieval Filtering):
[ Agent Query ] ──► [ Query Vector DB (Returns Top 20) ] ──► [ Application Filters ACLs ]
                                                                      │
                                                                      ▼
                                                       DATA ALREADY IN CONTEXT WINDOW!

Why this is a fatal flaw:

  1. Data Leakage into LLM Context: The vector database returned rows that the caller was not entitled to see. Even if your application code tries to drop unauthorized rows before displaying them on a screen, in an agent pipeline, those rows are frequently fed directly into the model's context window. Once in context, the information can influence model output or be written to debugging logs.
  2. Side-Channel Discovery: If an agent requests 10 items, but receives 0 items because all 10 were filtered post-retrieval, the attacker learns that matching documents exist but are restricted. The distinction between "no matching data" and "access denied" is a side-channel information leak.
✅ RIGHT (Query-Time Enforcement):
[ Agent Query + User Entitlement Claims ] ──► [ Storage Engine Injects Security Predicate ]
                                                              │
                                                              ▼
                                               Returns ONLY Authorized Rows

Authorization must be evaluated by the storage engine as part of query execution. If the caller lacks permission, the storage engine's execution planner must exclude those pages from disk reads entirely.


2. Embedding Vectors Are Not Hashes: Vector Inversion Attacks

Many security teams treat vector embeddings as "non-sensitive metadata" because they are arrays of floating-point numbers ([0.014, -0.891, 0.412, ...]). They assume that because raw text isn't visible in plain text, the vector store doesn't need the same security controls as the SQL database.

This assumption is dangerous.

Research in embedding inversion (such as Vec2Text) demonstrates that high-dimensional vector embeddings can be reconstructed into raw, human-readable text with over 80% exact phrase recovery.

┌────────────────────────────────────────────────────────┐
│ Vector Embedding: [0.014, -0.891, 0.412, ...]          │
└───────────────────────────┬────────────────────────────┘
                            │
                            ▼ (Embedding Inversion Model)
┌────────────────────────────────────────────────────────┐
│ Reconstructed Text: "Quarterly revenue for Account X   │
│ was $4.2M with 14% margin under NDA..."                │
└────────────────────────────────────────────────────────┘

If an enterprise locks down its PostgreSQL database but leaves its Qdrant / Milvus vector index exposed with weaker credentials, an attacker can query the vector index and reconstruct confidential data directly.

Rule: Vector indexes must be classified, encrypted, and access-controlled at the exact same sensitivity level as the source documents from which they were generated.


3. The Access Control List (ACL) Drift Problem

When a human employee changes departments or leaves a company, their user rights are updated in Active Directory / Okta.

In a traditional database, their access disappears instantly. But in a vector-backed RAG system, permissions are frequently baked into the vector metadata at ingestion time.

Day 1: Document A ingested with metadata {"department": "Finance"}.
Day 30: Document A reclassified to {"department": "Executive-Only"}.
Result: Vector index STILL holds {"department": "Finance"} metadata!

Unless your vector pipeline actively propagates ACL update events in real time:

  • Revoking a user's document access in SharePoint/Confluence does not revoke access in the vector index.
  • Deleting a source file leaves an orphaned embedding vector sitting in the index indefinitely.

The Fix: Dynamic Query-Time Entitlement Resolution

Do not store static role lists inside vector metadata tags. Instead, pass the user's cryptographically signed JWT entitlements at query time, and join against a live entitlement table:

-- Query-time authorization join inside PostgreSQL / pgvector
SELECT document_chunk, similarity
FROM document_embeddings e
JOIN document_acls a ON e.document_id = a.document_id
WHERE a.principal_id = $CURRENT_USER_ID
  AND e.embedding <=> $QUERY_VECTOR < 0.25
ORDER BY e.embedding <=> $QUERY_VECTOR ASC
LIMIT 5;

The 5 Data Substrate Health Metrics

To verify your data architecture holds under audit, monitor these 5 metrics:

  1. Index-to-Source ACL Lag: Time elapsed between a source ACL change and its enforcement in the vector index. (Target: < 30 seconds).
  2. Orphaned Vector Ratio: Percentage of vector embeddings whose source record no longer exists or is unreadable. (Target: 0.0%).
  3. Storage-Layer Denial Rate: Number of queries blocked by storage-level row security vs. application-level blocks.
  4. Context Window Contamination Rate: Incidents where non-entitled tokens reached an LLM execution window. (Target: Zero).
  5. Audit Ledger Hash Completeness: 100% verification that every data retrieval event is written to an immutable append-only storage ledger.

Summary

Data security for AI agents cannot be solved at the prompt layer or the application UI.

By enforcing row-level authorization inside the storage engine, treating vector embeddings as sensitive data, resolving ACLs dynamically at query time, and maintaining immutable audit ledgers, you build a data substrate capable of supporting autonomous agents safely.

Share this note
SUBSCRIBE TO FIELD NOTES

New Field Notes in your inbox.

We publish when we have something worth saying — reference architectures, benchmark tests, and engineering analysis. No cadence, no spam.