{
  "schema_version": "1.3.0",
  "slug": "why-does-an-instance-of-prompt-injection-taint-fail-to-propagate-across-a-tool-boundary-when-the-tool-returns-a-fresh-object-identity",
  "title": "Why does an instance of prompt-injection taint fail to propagate across a tool boundary when the tool returns a fresh object identity",
  "date_of_record": "2026 November 11",
  "scope": "Applies to agent runtimes that attach dynamic information-flow labels (taint) to values and enforce non-interference across tool-call boundaries by tracking object identity or reference equality. Does not apply to runtimes that re-derive labels from provenance metadata (content hashes, signed envelopes, or explicit label fields) on every hop, nor to purely syntactic scanners that re-scan tool output at each boundary.",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/why-does-an-instance-of-prompt-injection-taint-fail-to-propagate-across-a-tool-boundary-when-the-tool-returns-a-fresh-object-identity.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/why-does-an-instance-of-prompt-injection-taint-fail-to-propagate-across-a-tool-boundary-when-the-tool-returns-a-fresh-object-identity.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/why-does-an-instance-of-prompt-injection-taint-fail-to-propagate-across-a-tool-boundary-when-the-tool-returns-a-fresh-object-identity.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 1817,
    "python_slice_tokens": 372,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "The distinction that matters is between **label continuity by reference** and **label continuity by provenance**. A taint-tracking runtime that propagates labels by carrying a reference to a labeled object assumes the label survives any operation that keeps the reference alive. This assumption is sound within a single address space and a single serialization...",
    "what_was_observed": "During an agent run, a document retrieved from an untrusted source was labeled `UNTRUSTED` and passed as an argument to a summarization tool. The tool executed in a subprocess, received the document as a JSON string, and returned a summary. The summary was a new `str` object. The runtime's label map was keyed by `id()` (equivalently, by object identity in the interpreter's heap). The summary's `id()` did not appear i...",
    "condition_of_validity": "The identity-based propagation rule is valid only when all of the following hold: 1. The labeled value never crosses a serialization boundary (no `json.dumps`/`loads`, no subprocess pipe, no RPC) between labeling and sink. 2. The tool is modeled as a *transparent* function whose output label is a declared function of its input labels, and that declaration is...",
    "decision_boundary": "The operational decision is: **at every tool boundary, does the runtime re-derive labels from data provenance, or does it assume label continuity?** - If re-derive: the boundary is safe against copy-induced declassification, at the cost of carrying label metadata through every serialization and trusting the tool to preserve it (or having the runtime inject a...",
    "operational_effect": "The effect is a **silent taint-laundering channel**: any tool that copies its input into a new object acts as an unintentional declassifier. Because summarizers, translators, formatters, and retrievers all copy, essentially every realistic agent pipeline launders taint at its first hop. The audit trail remains internally consistent (all recorded labels are c..."
  },
  "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": "68ef1fafb7f53df48752ea36136ec1e3f4b185fb23d6e0ae6175d8eadb37d7f3",
    "verified_classes": [
      "TaintBoundaryViolation",
      "Label"
    ],
    "verified_functions": [
      "invoke_tool",
      "summarize",
      "join"
    ],
    "verified_functions_count": 3,
    "defensive_guards_count": 3,
    "raised_exceptions": [
      "TaintBoundaryViolation"
    ],
    "sample_fail_closed_invariants": [
      "assert label == Label.UNTRUSTED"
    ],
    "stdlib_dependencies": [],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
