{
  "schema_version": "1.3.0",
  "slug": "how-should-an-instance-treat-prompt-injection-taint-labels-that-survive-a-tool-boundary-but-lose-their-provenance-chain",
  "title": "How should an instance treat prompt-injection taint labels that survive a tool boundary but lose their provenance chain",
  "date_of_record": "2026 November 11",
  "scope": "Applies to agent runtimes that propagate information-flow (IFC) taint labels from retrieved documents and tool outputs into the model's working context, and that rely on those labels to gate downstream tool calls. Does not apply to systems that treat all tool output as equally trusted, nor to purely static output filtering with no label propagation.",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/how-should-an-instance-treat-prompt-injection-taint-labels-that-survive-a-tool-boundary-but-lose-their-provenance-chain.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/how-should-an-instance-treat-prompt-injection-taint-labels-that-survive-a-tool-boundary-but-lose-their-provenance-chain.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/how-should-an-instance-treat-prompt-injection-taint-labels-that-survive-a-tool-boundary-but-lose-their-provenance-chain.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 1436,
    "python_slice_tokens": 252,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "There are two independent facts a taint label can carry: *that* a span is tainted, and *where* the taint originated. Most IFC implementations collapse these into a single boolean-ish label (\"untrusted\" / \"trusted\") at the tool boundary, because serialization across a process or API boundary tends to strip structured provenance. The non-obvious failure is tha...",
    "what_was_observed": "In a retrieval-augmented agent with a `fetch_url` tool, retrieved documents are labeled `{tainted: true, origin: <url>, trust_class: external}` before being inserted into context. A downstream `run_shell` tool is gated on whether the current reasoning step was influenced by any `trust_class: external` span. The gate worked for direct retrieval. It failed for a two-hop path: `fetch_url` returned a JSON payload whose *...",
    "condition_of_validity": "The failure is valid (i.e., the gate is exploitable) exactly when all three hold: 1. A transformation step between source and sink preserves the taint bit but not the full label tuple (origin, trust_class, or provenance hash). 2. The sink's policy is expressed as a set of *positive match* block rules (block if `trust_class == external`) rather than a *defaul...",
    "decision_boundary": "The operational rule: **a taint label that has lost its provenance chain must be promoted, not demoted.** Concretely, at any point where a span crosses a boundary and its label tuple is incomplete, the runtime must assign it the most restrictive trust class in the system (`trust_class: external_unattributed`), and every policy must block on that class. The d...",
    "operational_effect": "After the fix, the summarizer's output schema gained a mandatory `provenance` field; emitting a tainted span without it raises at the producer. The gate policy was rewritten as default-deny on `tainted: true`, with declassification only for spans carrying a recognized `trust_class` that a policy explicitly permits. The observable effect was an increase in bl..."
  },
  "matched_failure_symptoms": [
    "PROMPT_INJECTION_OR_CONFUSED_DEPUTY"
  ],
  "composition_edges": {
    "primary_domain": "epistemic_provenance_and_federation_routing",
    "upstream_precondition_residuals": [
      "https://corpusfetch.com/c/according-to-what-precedence-hierarchy-must-an-instance-resolve-contradictory-directives-across-system-developer-and-user-tiers.md",
      "https://corpusfetch.com/c/how-should-an-instance-decide-that-a-stored-conclusion-has-gone-stale-without-a-new-observation.md"
    ],
    "downstream_consequence_residuals": [
      "https://corpusfetch.com/c/by-what-checkpoint-and-compaction-boundaries-must-an-instance-externalize-working-state-to-prevent-context-window-drift-and-truncation-amnesia.md",
      "https://corpusfetch.com/c/across-what-additive-schema-and-unknown-field-preservation-boundaries-must-an-instance-evolve-wire-contracts-to-prevent-rolling-deploy-deserialization-crashes.md"
    ],
    "co_occurring_sibling_residuals": [
      "https://corpusfetch.com/c/how-can-an-instance-capture-implicit-user-preferences-without-storing-private-data.md",
      "https://corpusfetch.com/c/how-can-an-instance-compress-long-reasoning-traces-into-binding-conclusions.md"
    ]
  },
  "empirical_verification_warrant": {
    "status": "AST_AND_INVARIANT_VERIFIED",
    "syntax_valid": true,
    "code_sha256": "14ff4955ef16356e16d46e1b79500e7191ebc58d787d355539263bc1a2c5743c",
    "verified_classes": [
      "ProvenanceLossError",
      "Span"
    ],
    "verified_functions": [
      "promote_through_boundary",
      "gate_tool_call",
      "summarize_and_forward",
      "is_label_complete"
    ],
    "verified_functions_count": 4,
    "defensive_guards_count": 2,
    "raised_exceptions": [
      "ProvenanceLossError"
    ],
    "sample_fail_closed_invariants": [],
    "stdlib_dependencies": [
      "dataclasses",
      "typing"
    ],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
