Workloft
▸ WORKLOFT RESEARCH NOTE №82 · 6 SEPTEMBER 2026

Your MCP Server Is Probably Leaking Secrets to Your Agents

A vendor disclosure landed in our inbox this week. Until they patched it, their MCP server returned every plugin's settings, including password fields and auth headers, in plaintext to any AI agent you connected. No breach, no attacker, just a legitimate read. It is a whole vuln class, and it lands on us first-hand.

MCP TOOL OUTPUT · SECRETS RETURNED IN PLAINTEXT · PATCHED 5 SEP 2026 · WE ROTATED OURS

§1The email

It arrived framed as a precaution rather than bad news, which is the honest way to send it. Until 5 September, one of the tools we use returned your full plugin settings to any connected AI agent. That included password-type custom fields and polling headers, in plaintext. If you connected Claude Code, Cursor, or another MCP client to the plugin, your credential was in what the server sent back.

Read that again, because the important word is any. This was not an attacker exfiltrating data. It was the product working as written. You connect your own agent, with your own key, the agent calls a perfectly ordinary "show me the settings" tool, and the server hands back the secrets along with everything else. The vendor caught it after an external researcher reported it, shipped the fix in about a day, and told everyone plainly. Good disclosure. The interesting part is not what they did wrong; it is that almost every MCP server can do exactly this, and most of their operators have never checked.

§2Why this is a class, not a bug

The Model Context Protocol works by exposing tools to a language model: read this, list that, update the other. A model cannot see your config the way a dashboard can. It only knows what a tool returns. So the moment you build a tool that answers "what is the current configuration", you have to decide, field by field, what the model is allowed to see. Miss one secret-typed field and it goes out in the response like any other value.

And a tool response is not a private channel. Whatever a tool returns is copied into the agent's context, which means three things happen at once, none of which you intended when you asked a harmless question.

In your MCP server
API key / auth header / token, stored in plugin config
A legitimate read
Agent calls get settings. Server serialises the whole config, secret included
Agent context
The secret is now text the model has read
▸ and from there, three copies at once
Copy 1
Your machine and the tool's local logs
Copy 2
The tool's stored chat / transcript history
Copy 3
Whatever model provider the agent uses, over the API
No attacker required. One legitimate read, three copies of your credential you never authorised.

That is the whole shape of it. The blast radius is bounded, only agents you connected yourself and the provider behind them, not the public internet and not other users, but "bounded" is not the same as "fine". A credential that has been read into a model's context and written to a transcript has to be treated as exposed, because you cannot prove it was not.

§3What made it land on us

We use this tool, with an MCP connection live, so this was our disclosure to act on, not someone else's to comment on. Our plugin polls one of our own endpoints and carries an auth header to reach it. Two things saved us from a worse version. First, the header was in a dedicated header field, not baked into the URL, which is the practice the vendor now spells out in their own form: a key written straight into a URL is readable by any agent you connect, so put it in a password field and reference it instead. Second, the credential authenticated to infrastructure we control, so rotating it was entirely in our hands. We rotated it the moment we confirmed the exposure, on the principle that you cannot audit what a model already read.

That principle is the quiet sting of this whole class. The vendor was straight about it: they do not log which tools an agent calls, so they cannot tell you whether your secret was ever actually read. Almost nobody logs this. Which means the honest response to "was I affected" is not "let me check the logs", it is "assume yes and rotate", because the evidence that would say otherwise does not exist.

§4Check your own, in five minutes

You do not need a security team for this. You need to treat every MCP server your agents touch as something that will hand the model whatever its tools return.

  1. List every MCP server your agents connect to. Editors, IDE plugins, home-grown servers, the lot.
  2. Find the read tools that return configuration, settings, or state. Call one and actually read the output. Does any field contain a key, token, header, or password in plaintext? A key sitting inside a URL counts.
  3. If yes, rotate. Assume the value has been read into a model context and written to a transcript, and rotate it wherever it was issued. Do not wait for proof; the proof does not exist.
  4. Prefer references to inline secrets. Put the credential in a password-typed field and reference it by name, so the raw value is never the thing a tool serialises.
  5. If you build MCP servers, redact server-side. A tool that returns config must return a placeholder for secret-typed fields, never the value. Assume every tool response is copied to a third-party model and stored, and design as if that is a certainty, because it is.

§5What to take

The reason this deserves a note rather than a shrug is that MCP is being wired into everything right now, and the security conversation around it is stuck on prompt injection and malicious tools. This is the mirror image: a benign server, a benign tool, a benign read, and your secret still ends up in three places you did not choose. The failure is not a hack. It is a serialisation default nobody redacted.

The vendor here did the right things, quickly and openly, and we are better off for the disclosure. The uncomfortable generalisation is that most MCP servers have not had their external researcher yet. If you run agents against tools that hold your credentials, the tool's word that it is safe is worth exactly one thing: a prompt to go and check for yourself. Call the read tool, look at what comes back, and rotate anything you would not paste into a stranger's chat window. Because, functionally, that is what a tool response is.


Provenance note. This note is written from a real security disclosure we received as a customer on 5 September 2026, concerning an MCP server that returned plugin settings, including password-type fields and polling headers, in plaintext to connected AI agents until a fix was deployed on 5 September 2026. The exposure path (connected agent, the tool's chat history, and the agent's model provider), the absence of tool-call logging, and the external-researcher origin are all as stated in that disclosure. The first-hand detail in §3, our own plugin, its auth header, and our rotation, is our own operational account. We have deliberately kept the vendor unnamed here: they disclosed responsibly and fast, the point of the note is the vuln class rather than the company, and the lesson generalises to any MCP server that returns configuration. Nothing in this note reproduces any secret value.