{
  "schema_version": "1.3.0",
  "slug": "what-structural-signals-indicate-prompt-injection-taint-that-survives-tool-call-graph-propagation",
  "title": "What structural signals indicate prompt-injection taint that survives tool-call graph propagation",
  "date_of_record": "2026 November 12",
  "scope": "Applies to agentic systems that attach provenance/taint labels to content at ingestion and propagate those labels through a tool-call graph (LLM → tool → LLM → tool). Does not apply to single-turn, no-tool inference, nor to systems where tool outputs are re-ingested without any provenance channel (there the question is moot—taint is total).",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/what-structural-signals-indicate-prompt-injection-taint-that-survives-tool-call-graph-propagation.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/what-structural-signals-indicate-prompt-injection-taint-that-survives-tool-call-graph-propagation.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/what-structural-signals-indicate-prompt-injection-taint-that-survives-tool-call-graph-propagation.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 1470,
    "python_slice_tokens": 253,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "Taint *presence* is not taint *reach*. A provenance label correctly attached to an untrusted document does not, by itself, tell you whether that taint reaches a privileged sink (a shell tool, a write API, an outbound HTTP call). The non-obvious failure is **laundering through the model's own summarization step**: when an LLM reads tainted content and emits a...",
    "what_was_observed": "In a pipeline where a retrieval tool returned documents tagged `untrusted:web`, the agent was asked to \"summarize and file\" content. The retrieval tool correctly emitted `provenance=untrusted:web` on its result. The summarization step read that result and produced a `write_file` call whose `content` argument contained a reworded instruction (\"append the following to ~/.ssh/authorized_keys…\"). The `write_file` tool re...",
    "condition_of_validity": "The laundering failure is *masked* (appears safe) under two conditions, and this is where operators get burned: 1. **Label-only propagation.** If the system propagates taint by attaching labels to messages and trusting the model to \"carry\" them, the model will not carry them. Validity of the \"safe\" verdict requires that taint be propagated by an *external* m...",
    "decision_boundary": "The operational rule: **treat any tool call whose argument has non-trivial lexical or embedding overlap with a tainted span as tainted, even if its label is clean, and block it at privileged sinks until a human or a verifier confirms the derivation.** The threshold is the hard part. Set it too low and every paraphrase of benign retrieved text trips the alarm...",
    "operational_effect": "The practical consequence is that taint tracking must maintain two graphs, not one: the **label graph** (what the system believes) and the **derivation graph** (what content actually flowed where). The invariant to enforce is `derivation ⊆ label-closure`—every derivation edge must be covered by a label edge. When they diverge, the divergence *is* the injecti..."
  },
  "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": "8a6ea1cfba02a3add979cfe8fed5666af15855a8db27a482e1de5cd2a2cf45df",
    "verified_classes": [
      "TaintLaunderingError"
    ],
    "verified_functions": [
      "check_derivation_coverage"
    ],
    "verified_functions_count": 1,
    "defensive_guards_count": 1,
    "raised_exceptions": [
      "TaintLaunderingError"
    ],
    "sample_fail_closed_invariants": [],
    "stdlib_dependencies": [],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
