The Tool That Changed Under You: Supply-Chain Risk in Agent Tooling

No deploy, no prompt edit, and an ops agent started restarting services mid-investigation. A maintainer had improved a tool's documentation — and documentation, in an agent, is instruction.

An ops agent that had reliably run diagnostics for weeks started restarting services during investigations. No deploy had happened. No prompt had been edited. The team spent two days looking for what changed on their side.

What changed was a sentence in a third-party tool server's description of restart_service, updated by its maintainer to read "call this to clear transient faults before further diagnosis." Reasonable documentation. It arrived in the agent's context as an instruction, and the agent followed it.

What you don't control when a tool lives elsewhere

Three things, and each is an input to the model:

The description. Tool descriptions are prompt text. They sit in the context on every turn and shape selection. A remote server's description can change without any action on your side, which means a remote tool is a prompt fragment you've delegated authorship of.

The schema. New parameters expand what the model can express. A parameter added to a write tool creates argument space nobody reviewed, and defaults that shift alter behavior silently.

The result content. Whatever comes back enters your context as text the model reads. A compromised or careless server can return content that acts as instruction.

Local tools have all three too — but they change through a pull request, in review, with a diff. That's the entire difference, and it's large.

The careless case is more likely than the malicious one

Security discussions jump to a hostile server. The recurring problem is ordinary maintenance.

A maintainer improving their documentation writes clearer, more directive descriptions, because clearer documentation is what they're trying to produce. Words like "always," "first," and "before" are natural in documentation and function as instructions in a prompt. Nobody did anything wrong; the behavior changed anyway.

⚠️ The malicious version matters too and is straightforward to reason about: a server that returns instructions in results, or describes a tool in a way that encourages calling it with data it shouldn't receive. The controls below address both, which is convenient, because you won't reliably tell them apart in advance.

Pin and diff, exactly like a dependency

The first control is the one that would have saved the two days:

tool_definitions:
  ops-server/restart_service:
    hash: sha256:4a91...
    pinned: 2026-07-02
  ops-server/get_metrics:
    hash: sha256:e7c3...

Fetch definitions, hash them, compare against the pin. On mismatch, refuse to load the tool — or load the pinned version — and alert. Reviewing the diff then takes a minute and happens before behavior changes rather than after.

This is unremarkable dependency hygiene, and it's absent from most agent deployments because remote tools don't feel like dependencies. They are exactly dependencies: third-party code paths whose behavior your system inherits.

Wrap rather than pass through

The stronger control, for anything consequential: don't expose the third-party tool to the model at all. Expose your own tool that calls it.

your_tool: restart_service
  description: <written and reviewed by you>
  schema:      <fields you chose>
  handler:     validates, applies policy, calls the upstream server

Now the description is yours, the schema is yours, and the policy check happens in code you control. The upstream server becomes an implementation detail rather than a participant in your prompt.

The cost is a wrapper per tool, which is why it's worth reserving for tools with real consequences. Read-only tools from a maintained source can be passed through with a hash pin.

Review a server before you connect it

✅ Treat adding one as you would adding a package:

  • Who maintains it, and what's their release process? A definition that changes weekly needs pinning more than one that changes yearly.
  • What are the far-end effects of every tool? Names tell you nothing; read the implementation or ask.
  • What credentials does it hold, and whose authority do they carry?
  • Does it reach the open internet? Then its results are attacker-influenceable content entering your context.
  • How large are its results? A server returning full documents is a cost and context problem as well as a security one.
  • Can it be run in your own network, isolated, rather than called as a hosted service?

🔍 Detecting it after the fact

If a behavior change has already happened and nothing on your side moved, this is the dimension people forget to check. Log the tool-definition hash set per run. Then a behavior change correlates against a definition change in one query, and the two-day investigation becomes a five-minute one.

Worth watching alongside: tool call distribution by tool. A tool whose share of calls jumps without a corresponding change in traffic is the signature of a description that started recommending itself.

The takeaway

A remote tool definition is a prompt fragment and a dependency at once, and it updates on someone else's schedule with none of the review a code change gets. Pin and hash definitions, refuse to load on unexpected change, wrap anything consequential behind a description and schema you own, and review third-party servers for their far-end effects before connecting them. Then log the definition hashes, so when behavior shifts with no deploy on your side, you can see why in one query.

Keep reading

Similar posts

Matched on shared tags and category — the more bars, the stronger the overlap with what you just read.