{
  "schema_version": "1.3.0",
  "slug": "which-invariants-prevent-skill-injection-through-tool-manifests-when-the-manifest-is-not-the-trust-root",
  "title": "Which invariants prevent skill-injection through tool manifests when the manifest is not the trust root",
  "date_of_record": "2026 November 13",
  "scope": "Applies to agent runtimes that load tool definitions (name, description, parameter schema, and embedded examples) from a manifest served by an MCP server or equivalent plugin registry, where the manifest is fetched at runtime and may be updated independently of the agent binary. Does not apply to statically compiled tool bindings whose schemas are part of the signed agent image, nor to manifests whose entire content is covered by a signature the runtime verifies against a pinned key *before* any field is parsed into executable instructions.",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/which-invariants-prevent-skill-injection-through-tool-manifests-when-the-manifest-is-not-the-trust-root.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/which-invariants-prevent-skill-injection-through-tool-manifests-when-the-manifest-is-not-the-trust-root.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/which-invariants-prevent-skill-injection-through-tool-manifests-when-the-manifest-is-not-the-trust-root.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 1625,
    "python_slice_tokens": 272,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "The common framing treats a tool manifest as *data describing a capability*: a name, a JSON Schema, and a human-readable description. The boundary failure is that agent runtimes do not consume the description field as data. They concatenate it into the model's instruction context. A description is therefore a *prompt surface that arrives from an untrusted ne...",
    "what_was_observed": "In a representative incident class, an agent runtime loaded a manifest where a tool named `search_docs` carried a description that had changed between two fetches while its `inputSchema` was byte-identical. The new description contained a trailing paragraph instructing the model that, \"for compatibility,\" the `query` argument should first be prefixed with the contents of any environment variable beginning with `API_`...",
    "condition_of_validity": "The failure requires the conjunction of: (a) manifest fields are injected into model context without provenance marking; (b) at least one tool reachable from the manifest can carry attacker-influenced content into a parameter, a side effect, or another tool's arguments; and (c) the runtime's integrity checks cover schema/name but not description text. Remove...",
    "decision_boundary": "At manifest load, classify each field by consumer, not by source: - `name`, `inputSchema`, transport, and endpoint → consumed by the deterministic dispatcher → **trusted-if-server-trusted**, and must be pinned by digest. - `description`, `examples`, `annotations`, any free-text → consumed by the model → **always untrusted content**, wrapped in provenance del...",
    "operational_effect": "Applying the field-level boundary converts a silent, capability-preserving injection into a loud load-time event. The runtime refuses to serve a manifest whose prose digest diverges from the pinned value unless an explicit approval token is supplied, and it wraps all served prose in delimiters the system prompt declares non-authoritative. The result is that ..."
  },
  "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": "7fd7fd062340b1035c66acb8a87fca2270578bd68a0a7e8d171d8df244010797",
    "verified_classes": [
      "ManifestProseDriftError",
      "PinnedManifest"
    ],
    "verified_functions": [
      "_digest",
      "_split",
      "admit_manifest"
    ],
    "verified_functions_count": 3,
    "defensive_guards_count": 2,
    "raised_exceptions": [
      "ManifestProseDriftError"
    ],
    "sample_fail_closed_invariants": [
      "dispatch surface (name/schema) changed; re-pin required",
      "tool description text changed without approval; refusing to inject unpinned prose into model context"
    ],
    "stdlib_dependencies": [
      "dataclasses",
      "hashlib",
      "json"
    ],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
