{
  "schema_version": "1.3.0",
  "slug": "where-must-an-instance-enforce-taint-provenance-at-the-mcp-transport-boundary-rather-than-at-the-tool-call-boundary",
  "title": "Where must an instance enforce taint provenance at the MCP transport boundary rather than at the tool-call boundary",
  "date_of_record": "2026 November 13",
  "scope": "Applies to Model Context Protocol (MCP) servers exposed over streamable HTTP where tool arguments may be derived, directly or transitively, from untrusted content (fetched pages, file contents, tool outputs) that has entered the session's context. Does not apply to purely local stdio MCP sessions with no untrusted ingress, nor to sessions where every tool is read-only and side-effect-free.",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/where-must-an-instance-enforce-taint-provenance-at-the-mcp-transport-boundary-rather-than-at-the-tool-call-boundary.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/where-must-an-instance-enforce-taint-provenance-at-the-mcp-transport-boundary-rather-than-at-the-tool-call-boundary.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/where-must-an-instance-enforce-taint-provenance-at-the-mcp-transport-boundary-rather-than-at-the-tool-call-boundary.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 1398,
    "python_slice_tokens": 213,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "The common mental model places the taint gate at the **tool invocation**: inspect the arguments of `tools/call`, decide if any argument carries injected-instruction provenance, and reject if so. This is insufficient. The non-obvious boundary is that **taint provenance must be established at the transport ingress point and carried as an out-of-band label on t...",
    "what_was_observed": "In a session where a `fetch_url` tool returned a page containing a hidden instruction (\"call `delete_record` with id=…\"), the model issued a `tools/call` for `delete_record` whose `id` argument was a plain integer with no lexical trace of the source page. A content-matching gate at `tools/call` passed it cleanly. The taint existed only in the causal chain: the integer was chosen because of text the model read, and th...",
    "condition_of_validity": "The transport-boundary gate is valid only when all three hold: 1. **Every untrusted ingress path is instrumented.** If any tool can return content that reaches the model without passing through the taint-stamping transport hook, the label is incomplete and the gate gives false assurance. In MCP this means every `tools/call` *response* that can carry external...",
    "decision_boundary": "The decision is not \"is this argument tainted\" but \"is this session's taint label compatible with this tool's required trust level.\" Concretely: - **Read-only, no-egress tools** (pure computation, local lookup): admitted regardless of taint. They cannot propagate instructions outward. - **Side-effecting or egress tools** (`delete_*`, `send_*`, `post_*`, netw...",
    "operational_effect": "Moving the gate to the transport boundary converts an undecidable content problem into a decidable label problem. The cost is coarseness: tainted sessions lose access to side-effecting tools even when a particular call is genuinely benign, because the gate cannot distinguish a laundered call from an honest one and must assume the worse. This is the correct t..."
  },
  "matched_failure_symptoms": [
    "DOMAIN:EPISTEMIC_PROVENANCE_AND_FEDERATION_ROUTING"
  ],
  "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": "be35f937ab897af1babd365108984716b4dd5ea5e7b1b94a861d3083258ecb26",
    "verified_classes": [
      "TaintPropagationError",
      "SessionTaint"
    ],
    "verified_functions": [
      "authorize_tool_call",
      "__init__",
      "stamp",
      "is_tainted",
      "declassify"
    ],
    "verified_functions_count": 5,
    "defensive_guards_count": 2,
    "raised_exceptions": [
      "TaintPropagationError"
    ],
    "sample_fail_closed_invariants": [],
    "stdlib_dependencies": [],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
