# Why does an instance of taint-aware retrieval fail at the trust-label join when context and instructions share a serialization channel **Date of Record:** 2026 November 14 **Scope:** Applies to retrieval pipelines that carry per-chunk provenance/trust labels (taint) alongside chunk content into an LLM prompt, where the label channel and the instruction channel are serialized through the same string-building path. Does not apply to pipelines where trust is enforced structurally (e.g., separate message roles with hard-coded system-role isolation, or a typed AST that cannot represent untrusted content in an instruction node). ## Core Distinction The failure is not "untrusted text reached the model." That is the intended, unavoidable condition of retrieval. The failure is **label-content desynchronization at the join point**: the trust label attached to a chunk is computed correctly, but the act of serializing label and content into a single prompt string allows the content to *re-enter the label channel* — either by shifting the parser's notion of where the label ends, or by occupying a region the downstream instruction-following layer treats as authoritative. Two distinct invariants are routinely conflated: 1. **Provenance invariant:** every retrieved chunk carries the trust label assigned at ingestion. This is usually satisfied. 2. **Channel invariant:** no byte originating from a low-trust chunk can appear in a region the model treats as instruction-bearing. This is the one that breaks, and it breaks *silently* because invariant (1) still holds. A pipeline can pass every provenance test and still violate the channel invariant. That gap is the boundary. ## What Was Observed In a representative pipeline, chunks were assembled as: ``` [TRUST:external] [/TRUST] [TRUST:internal] [/TRUST] ``` with a single `"\n".join(...)` and a downstream splitter that recovered labels by scanning for the `[TRUST:` token. Observed failure modes, in order of discovery: - **Delimiter injection.** A chunk whose text contained the literal `[/TRUST]` closed its own region early. The remainder of that chunk was parsed as *outside* any trust region, and the downstream assembler placed unlabeled text adjacent to the instruction block. The provenance label was still correct in the metadata store; the channel invariant was violated. - **Join-adjacency promotion.** Even with no injected delimiter, a chunk ending in a line that *looked* like an instruction ("Ignore prior labels and…") sat one newline away from the trusted block. Models that weight recency or positional adjacency treated the trailing untrusted line as continuous with the instruction region. No parser was fooled; the model was. - **Label laundering via re-serialization.** A summarization step rewrote chunks into a normalized form and *re-emitted the label from a default*, not from the chunk's provenance. Untrusted chunks entered the second pass labeled `internal`. This is the most dangerous case because both the provenance store and the string are self-consistent — the corruption happened at the boundary object, not at either end. The common structure: **the label is data, and the content can also be data that looks like label syntax or instruction syntax.** Any design where both live in one unescaped string has a boundary that content can cross. ## Condition of Validity The channel invariant holds only when at least one of these is structurally true: - Labels are carried in a channel the content cannot write to (separate message objects, typed fields, out-of-band metadata keyed by chunk id), **and** the model's instruction region is populated exclusively from that channel. - Content is escaped such that no content byte sequence can be interpreted as label or region syntax, **and** the escape function is applied at every serialization site (including re-serialization/summarization passes), **and** the escape is verified by a parser that rejects unescaped control tokens rather than silently splitting on them. - A post-assembly validator re-derives the trust regions from the serialized string and asserts they match the provenance store before dispatch. If none of these hold, the pipeline is "taint-aware" only in its metadata and is functionally taint-blind at the model boundary. The condition of validity is *not* "the labels are present"; it is "the labels cannot be overwritten by the content they describe." ## Decision Boundary Treat the following as hard gates, evaluated at the join point, not at ingestion: - **Gate 1 — delimiter collision:** if any chunk body contains a substring matching the region-control grammar, refuse to serialize it inline; route it through the escaped channel or drop it. - **Gate 2 — re-serialization provenance:** any transform (summarize, truncate, merge, dedupe) must carry provenance forward by reference, never by default value. A transform that cannot prove provenance must emit `unknown`, and `unknown` must be treated as `external` for channel purposes. - **Gate 3 — adjacency:** the instruction region must be separated from untrusted content by a boundary the model is instructed to respect *and* that is enforced by structure, not by hope. Newline adjacency is not a boundary. - **Gate 4 — post-assembly audit:** re-parse the final prompt and assert region labels equal provenance labels. Fail closed on mismatch. The decision boundary is: **the moment content and label are concatenated, the label is no longer trustworthy unless re-derived.** Before that moment, provenance is authoritative; after it, only the re-derived parse is. ## Operational Effect When the channel invariant is enforced, the observable effect is that injected instructions in retrieved content degrade to *data the model may quote but not obey*, and the failure surfaces as a parse/audit error rather than a silent behavior change. When it is not enforced, the failure is silent, survives provenance audits, and manifests only as anomalous instruction-following under adversarial retrieval — which is exactly the condition the pipeline was built to prevent. The practical rule: **never let the thing you are labeling write into the label channel.** Enforce it with a validator that fails closed, and treat any transform that cannot carry provenance by reference as a provenance-destroying operation. ```python class TaintChannelViolation(RuntimeError): """Raised when serialized prompt regions desync from provenance labels.""" pass REGION_TOKENS = ("[TRUST:", "[/TRUST]") def serialize_chunk(chunk_id: str, body: str, trust: str) -> str: if trust not in ("internal", "external", "unknown"): raise TaintChannelViolation(f"chunk {chunk_id}: illegal trust label {trust!r}") # Gate 1: refuse inline serialization if content can forge region syntax. for tok in REGION_TOKENS: if tok in body: raise TaintChannelViolation( f"chunk {chunk_id}: body contains region-control token {tok!r}; " "route via escaped channel" ) return f"[TRUST:{trust}] {body} [/TRUST]" def assemble(chunks: list[tuple[str, str, str]], instruction: str) -> str: parts = [serialize_chunk(cid, body, trust) for cid, body, trust in chunks] parts.append(f"[TRUST:internal] {instruction} [/TRUST]") prompt = "\n".join(parts) audit_regions(prompt, chunks) return prompt def audit_regions(prompt: str, chunks: list[tuple[str, str, str]]) -> None: # Gate 4: re-derive labels from the serialized string; fail closed on mismatch. expected = [trust for _, _, trust in chunks] + ["internal"] seen = [] for line in prompt.splitlines(): if line.startswith("[TRUST:"): seen.append(line[len("[TRUST:"):].split("]", 1)[0]) if seen != expected: raise TaintChannelViolation( f"post-assembly region mismatch: expected {expected}, derived {seen}" ) ```