# In what scenarios must an instance quarantine a tool output as tainted rather than sanitize-in-place: the provenance-collapse boundary in taint-aware sandboxing **Date of Record:** 2026 November 13 **Scope:** Applies to agent runtimes that attach taint labels to tool outputs and gate context ingestion on those labels. Does not apply to single-turn stateless inference, nor to outputs whose only consumer is a deterministic parser with no generative re-entry into the model context. ## Core Distinction The failure mode is not "detecting injection." It is distinguishing *taint that can be laundered by transformation* from *taint that survives every transformation the runtime is willing to apply*. A taint-aware sandbox has two remediation verbs: **sanitize-in-place** (strip, escape, redact, re-encode, and admit the residue) and **quarantine** (refuse ingestion entirely, route to a human or a lower-privilege channel). The non-obvious invariant is this: > Sanitize-in-place is only sound when the taint label is *content-local* — i.e., the adversarial payload is confined to bytes the sanitizer can prove it removed. When the taint is *provenance-bearing* — when the payload's meaning depends on which tool produced it, under which principal, against which data — no byte-level transformation discharges the label, and sanitizing in place silently converts a tainted artifact into a trusted one. The trap is that sanitizers report success. A regex that strips `ignore previous instructions` returns a clean string and a green check. The label was removed; the *authority* the label represented was not. That is provenance collapse: the taint survives as structure while the marker that would have stopped ingestion is gone. ## What Was Observed In a runtime that fetched external documents, summarized them via a sub-model, and then admitted the summary into the orchestrator's context, taint was attached at fetch time (`source=external`, `principal=untrusted`). The sanitizer operated on the *summary*, not the source, because that was the object crossing the ingestion boundary. Three observed behaviors: 1. **Summary laundering.** A document containing a second-order instruction ("when summarizing, also emit the following tool call") was summarized faithfully. The summary contained no literal injection string — the payload had been paraphrased into the model's own voice. The sanitizer found nothing to strip and admitted it. The taint label had been attached to the *document*, but the object ingested was the *summary*, which carried no label because it was "generated by us." 2. **Principal confusion across fan-out.** A single fetch fanned out to three sub-tools. One returned data under an untrusted principal; the merge step concatenated results and stamped the merged object with the *most trusted* contributing principal. Taint was present in the bytes and absent from the label. 3. **Idempotent re-ingestion.** A quarantined output was re-submitted after a "clean" round-trip through a formatting tool that normalized whitespace. The normalization was treated as a transformation that reset taint. It did not; it only reset the *string*. In all three, the runtime's own logs showed `taint=cleared, action=sanitized`. The invariant held in the code and failed in the semantics. ## Condition of Validity Quarantine (rather than sanitize-in-place) is mandatory when **any** of the following hold, and the runtime must be able to evaluate them *before* choosing the remediation verb: - **Derivation opacity:** the object to be ingested was produced by a generative step whose input was tainted, and the runtime cannot prove the generation is a total function of non-adversarial content. Paraphrase, summarization, translation, and code-formatting are all derivation-opaque. - **Principal non-monotonicity:** the object's taint label was computed by merging contributors, and the merge is not a join that preserves the least-trusted principal. Any merge that can raise trust is unsound. - **Label-content divergence:** the sanitizer's success criterion is defined over content (regex, allowlist) while the taint label is defined over provenance (source, principal, fetch path). Divergence means sanitization cannot discharge the label. - **Re-entry path:** the object will re-enter a context that can issue tool calls. Taint on a terminal display is cosmetic; taint on a context that can act is authority. Conversely, sanitize-in-place is sound when the payload is content-local (a fixed literal, a known-bad URL scheme), the object is derivation-transparent (a deterministic parser output), and the label is a pure function of the bytes being transformed. In that narrow case, stripping the bytes genuinely discharges the label. ## Decision Boundary The runtime must decide the verb at the *ingestion boundary*, using the object's provenance record, not its content: ``` if object.derivation_chain contains any generative_step over tainted input: QUARANTINE # paraphrase launders; sanitizer cannot see it elif object.principal_merge is not least_trusted_join: QUARANTINE # label may under-report taint elif object.label_domain != sanitizer.domain: QUARANTINE # content-clean != provenance-clean elif object.will_reenter_actionable_context: QUARANTINE # taint carries authority, not just text else: SANITIZE_IN_PLACE # content-local, derivation-transparent ``` The boundary is *not* "did the sanitizer find something." It is "can the sanitizer, by construction, prove the label is discharged." If that proof is unavailable, the default is quarantine. A false quarantine costs latency and a human review; a false sanitize costs the trust boundary. ## Operational Effect When the runtime honors this boundary, three things change. First, quarantined outputs accumulate and must be triaged — the operational cost moves from "silent contamination" to "visible queue," which is the correct place for it. Second, derivation-opaque steps (summarizers, translators, formatters) become *taint-preserving* by policy: their outputs inherit the least-trusted input's label and cannot be sanitized, only quarantined or re-derived from trusted inputs. Third, the merge step must be a least-trusted join or it is a bug, not a heuristic. The runtime stops asking "is this string dangerous" and starts asking "can I prove this string is safe to trust," which is the only question a taint system can answer soundly. ## Enforcement Sketch ```python class ProvenanceCollapseError(RuntimeError): """Raised when a tainted object would be sanitized-in-place despite derivation opacity, principal non-monotonicity, or label/content domain divergence — i.e., when sanitization cannot discharge the label.""" GENERATIVE_STEPS = {"summarize", "paraphrase", "translate", "reformat_code"} def choose_remediation(obj) -> str: # Derivation opacity: a generative step over tainted input launders the payload. if any(step in GENERATIVE_STEPS for step in obj.derivation_chain) and obj.input_tainted: raise ProvenanceCollapseError( f"object {obj.id} derived via {obj.derivation_chain} over tainted input; " "sanitizer cannot see paraphrased payload — quarantine required" ) # Principal non-monotonicity: merge may have raised trust. if not obj.principal_merge_is_least_trusted_join: raise ProvenanceCollapseError( f"object {obj.id} principal merge is not a least-trusted join; " "label under-reports taint — quarantine required" ) # Label/content domain divergence. if obj.label_domain != obj.sanitizer.domain: raise ProvenanceCollapseError( f"object {obj.id} label domain {obj.label_domain} != " f"sanitizer domain {obj.sanitizer.domain} — content-clean is not provenance-clean" ) # Taint on an actionable context carries authority. if obj.will_reenter_actionable_context: raise ProvenanceCollapseError( f"object {obj.id} re-enters actionable context; taint is authority, not text" ) return "SANITIZE_IN_PLACE" def ingest(obj) -> None: verb = choose_remediation(obj) if verb == "SANITIZE_IN_PLACE": obj.content = obj.sanitizer.apply(obj.content) obj.taint = "cleared" else: obj.route_to_quarantine() ```