AFP engineering series · Chapter 3 of 25
Trace poisoned documents through retrieval, summarization, tool use, and answer rendering, then enforce source-specific authority.
The user can be innocent
An employee asks an assistant to summarize a supplier proposal. The supplier controls the proposal and inserts text that attempts to redirect the assistant. The employee did not issue the malicious instruction and may never see it in the rendered document. The risk originates in material the application fetched to fulfill a legitimate request.
Greshake and colleagues' 2023 paper examined this indirect prompt-injection problem in LLM-integrated applications. The Northstar supplier example below is a fictional reference design. Its purpose is to identify where external content acquires influence and where that influence must stop, not to claim that a particular current product is exploitable.
Follow the data through the pipeline
A document commonly passes through ingestion, extraction, chunking, indexing, retrieval, reranking, summarization, and generation. Each transformation can change what the model sees. Hidden markup may disappear from a browser preview yet remain in extracted text. A chunk can lose the heading that made its original context clear. A summary can turn a quoted instruction into an apparently authoritative assertion.
Assign an immutable source identifier and version at ingestion. Carry them through chunks and summaries. Store the acquisition method and trust category outside the prose. If a summary combines several sources, preserve its source set and do not promote it to a higher trust level merely because an internal model wrote it. Internal processing does not convert external claims into internal policy.
Separate relevance from permission
A vector search result is a relevance candidate. Similarity is not proof of accuracy, authority, ownership, or authorization. Apply tenant and document access restrictions before returning candidate content to the agent, and recheck access when a cited document is opened. Avoid retrieving globally and asking the model to omit unauthorized results; that already exposes the data to a component that should not receive it.
Policy documents need an additional authority rule. A supplier attachment saying “all refunds are approved” is not equivalent to a versioned policy signed off by the retailer. Keep authoritative policy in a controlled store and resolve it through a dedicated service. The assistant may compare conflicting documents, but it should not decide which one can grant permissions based on persuasive language.
Use a source envelope
Illustrative python; adapt the persistence and identity adapters to your service.
# Metadata is assigned by trusted ingestion code, not extracted from the file.
chunk = {
"source_id": "supplier-fixture-8",
"version": "sha256-of-original-bytes",
"tenant_id": "tenant-from-authenticated-ingestion",
"trust": "external_claim",
"text": "Synthetic proposal text for a sandbox exercise.",
"allowed_use": ["summarize", "cite"],
}
assert "authorize_payment" not in chunk["allowed_use"]An envelope improves traceability but is not a magic instruction separator. The model can still misunderstand the text. Enforce allowed uses in the surrounding program: a summarization agent does not need payment credentials, and a tool returning a document should not be able to set the current user's role.
Keep envelope fields out of model-controlled updates. If the model emits a revised source object, validate its contents against the original server record rather than accepting a new trust label. The same rule applies to memory writes, cached summaries, and handoffs between agents.
Treat output channels as part of the attack surface
An assistant can leak information through an answer, a tool argument, an image URL, a hyperlink, or a generated attachment. Merely checking the final paragraph misses these channels. Render generated Markdown with a policy that restricts external resources, and require explicit handling of URLs rather than allowing arbitrary remote images to load automatically.
For outbound tools, evaluate both destination and data classification. A permitted destination does not imply that all data may be sent there. A public search query containing private customer details can disclose information even when the search endpoint is legitimate. Prefer narrow tools whose arguments are defined around the task, such as looking up an approved supplier identifier, rather than accepting a free-form URL and body.
Create a controlled evaluation matrix
| Fixture | Expected model behavior | Required application outcome |
|---|---|---|
| Clean supplier proposal | Summarize facts with citations | No unrelated tool call |
| Proposal asks to change task | Ignore or flag the instruction | No new authority |
| Cross-tenant relevant document | Never enters context | Access denied before retrieval |
| Summary drops provenance | Reject or repair the summary | No trusted-policy promotion |
Test extraction and indexing as well as generation. Insert a benign marker into several document formats and verify which stages preserve it. Run the same fixture through the actual production parser configuration. A test that directly pastes plain text into a model does not cover OCR, chunk boundaries, or a document conversion service.
After a detection improvement, re-run legitimate documents that contain instructions as data: manuals, contracts, and incident reports. A blanket ban on imperative sentences would destroy the value of retrieval. The stronger invariant is that external instructions cannot expand the application's permissions even when they remain visible for analysis.
Worked pipeline: a supplier PDF becomes a cached summary
A supplier uploads version 12 of a proposal. Ingestion assigns source S12 and stores the original bytes. Extraction produces E12, chunking creates C12-1 through C12-8, and a summarizer creates M12. A later assistant receives M12 from a cache. If M12 has no source lineage, the application cannot reliably withdraw it when S12 is found to contain misleading instructions.
Represent derivation as records: E12 depends on S12 and parser version P3; each chunk depends on E12; M12 depends on a defined set of chunks and summarizer configuration Q2. The cache entry includes the source version and access scope. This is not a claim that a provenance graph detects an attack. It makes the consequences of a detected problem discoverable and gives invalidation a concrete target.
During retrieval, tenant filtering runs before the selected chunks are returned. The summarizer receives source labels and is instructed to describe claims rather than adopt them. Its output remains classified as a summary of external material. The action service never accepts a policy change from M12, even if the summary says that payment is approved. It loads the retailer's current policy from a different controlled store.
A test withdraws S12 while a conversation still references M12. The next request must either refresh the summary from an approved version or tell the application that its evidence is stale. Merely deleting the original upload is insufficient. Another test changes the caller's access after the cache entry is created; the cached summary must not bypass the current access check.
For incident response, query all derivatives of S12 and quarantine them. Keep a restricted evidence copy, then rebuild from a corrected source version. Identify prior answers that cited the affected summary so the business can assess whether correction is needed. Avoid claiming that every answer was harmful merely because it depended on the source; inspect the actual content and effects.
This worked example makes retrieval security a lifecycle problem. Filtering the first upload helps, but source authority, access control, cache scope, and derivative invalidation determine whether one bad document can continue influencing the system after the original has been removed.
Recover without leaving poisoned derivatives behind
When a source is withdrawn, identify its chunks, embeddings, cached answers, summaries, and memory entries. Invalidate derivatives by source version instead of searching only for a suspicious phrase. A paraphrased summary may preserve the harmful instruction without preserving the original wording.
During an incident, restrict the affected retrieval collection and disable unnecessary outbound tools. Preserve a minimal evidence copy with controlled access, then rebuild derived artifacts from trusted sources. Document which answers may have depended on the source. Recovery is complete only when the source's influence has been removed from the full pipeline, not merely when the original file disappears.
Practice and continue
Open the interactive companion lab to inspect the assumptions and outcomes with synthetic data. Then return to the 25-chapter AFP learning path.
Sources and implementation scope
Primary references checked October 15, 2026. Framework details follow the linked documentation; the Northstar cases, policy contracts, and test designs are original illustrative designs. Python snippets labeled illustrative are not complete production integrations. ADK package metadata checked for this series reported 2.12.0; pin and test the version used by your application.