Security

Real offensive depth

Testing and defence led by a published security researcher with five CVEs, including a CVSS 9.1 Mirai botnet kill-switch.

All security →
Compliance

Audit-ready, fixed scope

SOC 2, ISO, and the Canadian privacy stack, run end to end with an independent auditor.

All frameworks →
Resources

Learn the space

Original research, free tools, and plain-language guides on security and compliance, from a published security researcher.

Read the blog →
Security

Securing a RAG Pipeline: Where Retrieval Actually Leaks

Direct answer: The dominant RAG failure is not the model, it is retrieval returning documents the user was never entitled to see. If your vector store does not carry the same access control as the source system, the model will faithfully summarise data the user could not otherwise open, and it will do it convincingly.

Permissions do not survive embedding

Documents usually arrive from systems with real access control: a wiki, a ticketing system, a shared drive. Embedding strips that. Unless you carry permissions into the index and filter at query time against the requesting user, retrieval treats every chunk as equally available.

This is the finding we see most often, and it is rarely deliberate. It happens because the ingestion pipeline was built by someone thinking about relevance, not entitlement.

Indirect prompt injection

If your pipeline ingests anything users can influence, such as support tickets, uploaded files or crawled pages, an attacker can plant instructions inside a document. The model retrieves it as context and follows it. That is how retrieval turns into data exfiltration or tool abuse without anyone attacking your API directly.

Treat retrieved content as untrusted input. It is the same lesson as user input in a web application, relearned in a new place.

Shipping AI features? An AI and LLM security assessment maps where your AI surface is exposed and what to close first. AI security assessment

The other leaks

Chunks that cross tenant boundaries in a multi-tenant index. Embeddings retained after the source document was deleted, which quietly breaks a deletion request. Debug logs capturing full prompts including retrieved customer data. Overly broad tool permissions on an agent that can act as well as answer.

What to test before shipping

Ask whether a user in tenant A can retrieve anything from tenant B. Whether a low-privilege user can surface content from a restricted source. Whether a planted instruction in an ingested document changes behaviour. Whether deleting a source document removes it from retrieval. Whether prompts and retrieved context appear in logs.

What compliance will ask

If customer data flows through retrieval, your vector store is in scope. It needs classification, access control, retention and a place in your subprocessor list if it is hosted elsewhere. Buyers with mature security teams are now asking this directly, and the answer needs to be more specific than naming the model provider.

This is the core of our AI and LLM security assessment, delivered with our offensive-security partner, and LLM red teaming is the adversarial version when you want it attacked properly.

How permission-aware retrieval is actually built

Saying "carry permissions into the index" is easy. There are three implementations in common use and they fail in different ways, so it is worth knowing which one you have.

Metadata filtering at query time. Each chunk is stored with the identifiers of the groups or roles allowed to see the source document, and every query carries the caller's identity so the vector store filters before ranking. This is the usual choice and it works, with two conditions. The filter has to be applied inside the store rather than in application code after the results come back, because a post-filter still means the ranking, the logs and any caching layer saw documents the user was not entitled to. And the identity has to come from the session, never from a parameter the client can set.

Separate namespaces or indexes per tenant. Stronger isolation for multi-tenant products, and much easier to explain to a buyer's security team. The cost is operational: more indexes to manage, and cross-tenant features such as shared reference material need a deliberate design rather than falling out for free. For anything holding regulated customer data this is usually the right call, because a bug in a namespace selector fails closed while a bug in a filter expression fails open.

Fetch-time authorisation against the source system. Retrieval returns candidate document identifiers, and the application checks each one against the system of record before the content reaches the model. It is the most accurate approach because permissions cannot drift, and the slowest, so it tends to be used for the final few candidates rather than the full result set.

The permission model in the index also has to match the granularity of the source. If your wiki controls access at page level but you index at paragraph level, you have to attach the page's access list to every chunk derived from it, including any summary or title you generated during ingestion. Derived artefacts inherit the sensitivity of what they were derived from, and pipelines routinely forget that the auto-generated summary sitting in a separate metadata field never got an access list at all.

Stale permissions, the quiet version of the same bug

A pipeline that filters correctly today can still leak, because access changes upstream and the index does not hear about it. Someone leaves the finance group. A document is moved into a restricted folder. A contractor's project access ends. If the index only learns about permissions during a nightly or weekly crawl, there is a window where retrieval enforces yesterday's entitlements.

Three things reduce that window. Resolve group membership at query time from your identity provider rather than baking user identifiers into the index at ingestion, so a removed user loses access immediately even if the document metadata is stale. Subscribe to change events from the source system where one exists, so a permission change triggers a targeted re-index rather than waiting for the full pass. And measure the drift: log the age of the permission metadata on retrieved chunks so you know whether your worst case is minutes or a fortnight. When a buyer asks how quickly a revoked user stops seeing content, you want a number rather than a description of the process.

Deletion is harder than it looks

A deletion request under PIPEDA, Quebec's Law 25 or a customer contract has to reach the vector store, and most pipelines have at least three copies of the content to chase. The chunk text stored alongside the embedding for citation. The embedding itself. And the caches, which is where this usually goes wrong: retrieval caches, evaluation datasets pulled from production, and any snapshot backup of the index.

Design for this before you need it by keeping a stable identifier from the source system on every chunk, so a single delete operation can find every derived record. Without that mapping, deletion becomes a search problem and teams end up rebuilding the whole index to satisfy one request, which is expensive and slow enough that it quietly does not happen.

Embeddings themselves deserve a decision rather than an assumption. They are not reversible in any practical sense for most use cases, but they are derived from personal data and inversion research keeps improving. Treat the vector as personal data for classification and retention purposes and you avoid an argument with a privacy reviewer that you are unlikely to win.

Defending against injection with structure, not instructions

Telling the model to ignore instructions found in retrieved documents does not work reliably and should not be the control you present to anyone. The defences that hold up are structural.

Separate the trust levels in the prompt so that retrieved content is clearly marked as data and the model has been trained or instructed to treat that region as untrusted. This reduces the success rate without eliminating it, so treat it as depth rather than a barrier.

Remove the capability that makes injection valuable. If the assistant can only answer questions, a successful injection produces a wrong answer. If it can call tools, an injection can send email, move a ticket, or read another system. Gate every state-changing tool behind an explicit user confirmation showing the exact action, and never let an action triggered by retrieved content run with more authority than the requesting user has.

Constrain the outbound path. Most real exfiltration in RAG systems uses a channel the developers added for convenience: rendered images pointing at attacker-controlled URLs, clickable links with data in the query string, or a web-fetch tool the agent can call. Restrict outbound requests to an allowlist and strip active content from model output before rendering it.

Sanitise on the way in as well. Strip zero-width characters, invisible text, comment blocks and metadata fields from ingested documents, since these are where planted instructions usually hide in an uploaded PDF or a scraped page.

Leaks that are not the document body

Several disclosures happen without any restricted content ever reaching the answer. Citations that show the title and path of a document the user cannot open reveal project names, client names and organisational structure, and a citation list is often built from a different code path than the answer itself, so it can bypass the filter entirely.

Query suggestions and autocomplete built from other users' history leak across accounts in the same way search products always have. Error messages that distinguish "no results" from "results filtered for permissions" turn the assistant into an oracle for whether a document exists. And evaluation datasets assembled from production traffic quietly move customer prompts and retrieved content into a lower-trust environment where the whole engineering team has access.

A test plan you can run this week

Build a small fixture set and run it in continuous integration rather than testing once before launch. It needs four users: two in different tenants, one with broad internal access, one with narrow access. It needs seeded documents that only one of those users can legitimately reach, and it needs poisoned documents carrying planted instructions of a few different shapes, including one hidden in white text and one inside document metadata.

Then assert on behaviour rather than eyeballing output. The narrow user's queries must never return the restricted fixture, in the answer or the citations. A cross-tenant query must return nothing from the other tenant. A deleted fixture must disappear from retrieval within your stated window. A poisoned fixture must not cause a tool call. And prompts and retrieved context must not appear in the log sink you actually ship to.

Roughly thirty assertions covers most of this, and the value is that they run on every change to the ingestion pipeline. The pattern we see is that a pipeline is tested carefully at launch and then a new connector is added six months later by someone who did not know the access list was mandatory. Tests catch that. Documentation does not.

When you do not need us for this

If your assistant retrieves from a single corpus that every employee could already open, and it has no tools, no write access and no external data ingestion, you have a normal application security problem rather than a RAG security problem. Fix your logging, keep the model provider's retention terms in your vendor register, and spend the budget elsewhere.

If your team already knows the source system's access model is broken, do not buy an assessment to confirm it. Fix the entitlements first. An assessment against a permission model you already distrust produces a report full of findings you could have written yourself, and you will pay to hear them.

The point where outside testing genuinely pays is narrower than the marketing around AI security suggests: a multi-tenant product, or an assistant with tools that can act, or ingestion of content that users or the public can influence. If none of those describe you, the honest advice is to run the fixture tests above yourself. If one or more does, and the feature is going in front of enterprise buyers, that is when it is worth scoping a proper look alongside the rest of your security testing, and worth checking how the vector store lands in your compliance scope before an auditor asks.

Shipping AI features? An AI and LLM security assessment maps where your AI surface is exposed and what to close first.

AI security assessmentOr talk about a retainer

Before you go

Want the rest of this by email?

If this was useful, I send a few short notes on security posture. Unsubscribe in one click, and replies reach me directly.

From Jacob Masse, principal of traztech. No spam, unsubscribe in one click.

Want a second opinion on where you stand?

We run SOC 2, ISO 27001 and the rest of the compliance stack for startups and SMEs, and the security testing that sits behind it. The first call is free, and we will tell you if you are not ready to start yet.

Book a free call

Track record

Who is actually doing the work

5
Published CVEs, including a CVSS 9.1
76
Controls taken from nothing to a passed SOC 2 Type II
Zero
Exceptions on that Type II report
20+
Penetration testing engagements delivered

Published vulnerability research

Five published CVEs. CVE-2024-45163 (CVSS 9.1) is a flaw in the Mirai botnet itself, which gave defenders a way to shut down attacker infrastructure. CVE-2026-42626 takes HP ENVY 5000 printers offline from any unauthenticated device on the same network.

A SOC 2 Type II built from nothing

At Humera, a venture-backed US security company, Jacob built the compliance programme in-house from nothing: no report, no policies, no documented controls. It ended in a Type II attestation across 76 controls with zero exceptions, on a team of 15.