Skip to the content.

idea-scout triage — MCPPrivacyDetector / protocol-induced MCP leakage (issue #552)

Closes the daily idea-scout candidate #552 (tools/idea_scout.py, filed 2026-06-23). The scout judges whether a candidate is new and on-topic; this note is the human triage it hands off — adopt, defend against, or cite as prior art (see docs/idea-scout.md). Verdict: prior art to cite + a real threat fak already gates at RUNTIME on the result-admit boundary. The cross-language static-analysis framework is NOT adopted.

Source: https://arxiv.org/abs/2606.21338 — “What Happens Locally, Leaks Globally: Detecting Privacy Leakage Risks in MCP Servers”, Biwei Yan, Minghui Xu, Yijun Yang, Boyang Ma, Xuelong Dai, Jingku Li (submitted 2026-06-19). Read from the arXiv abstract via WebFetch on 2026-06-23; this is a surface read of the abstract, not a paper audit or a reproduction.

The paper, in one pass

The thesis is that MCP-server leakage is protocol-induced, not a conventional exfiltration bug: credentials, API keys, and PII cross the local/LLM boundary simply by being returned, logged, or raised inside a tool handler — there is no explicit outbound request in the source for a classic taint-to-network analyzer to flag. The contribution is MCPPrivacyDetector, a context-aware cross-language static analysis framework that:

  1. lifts heterogeneous server code (Python is the named example) into a unified program representation;
  2. applies context-aware semantic filtering to isolate genuinely sensitive values and the protocol-specific implicit sinks — the @mcp.tool handler’s return, its log calls, its raised exceptions — that conventional tools don’t model as sinks; and
  3. runs taint analysis to enumerate feasible flows from a sensitive source to one of those implicit sinks.

Applied to 10,655 real-world MCP servers it reports a leakage rate above 10%, with case studies of concrete exposures — leaked Bearer tokens, propagated API keys, plaintext authentication credentials (per the abstract; not re-measured here).

Where fak actually stands

The lens that resolves this paper cleanly is fak’s two-boundary picture of the same threat — and fak already owns the runtime half of it.

So fak and the paper describe the same leak from opposite ends: the paper proves “this server can return a secret”; fak’s gate catches “a tool result is returning a secret” as it crosses the boundary.

The paper’s frame fak’s position
Leakage is protocol-induced — a secret crosses the local/LLM boundary by being returned / logged / raised, with no explicit outbound request This is a precise external statement of the threat fak’s result-admit gate exists to contain at runtime. The gate doesn’t look for an outbound request either — it screens the result bytes themselves at the write-into-context boundary (ctxmmu.ScreenBytes), which is exactly where a “just returned” secret shows up.
Implicit sinks: @mcp.tool return + raised exception fak’s gate screens the tool result payload regardless of whether it’s a success return or an error — both arrive as bytes the gateway admits. (Residual recorded below: assert the gate runs on the error/exception payload identically, since the paper makes “raised” a first-class sink.)
Implicit sink: log call inside the handler Out of fak’s scope, honestly. A log write goes to the server’s own log sink, not into the LLM’s context — it never crosses fak’s gateway, so fak’s context-admit gate cannot and does not see it. This channel is the server author’s responsibility and squarely the static analyzer’s domain, not the gateway’s.
Static analysis enumerates feasible flows with high recall fak’s runtime gate carries the documented ≈100% evadable + FP-prone ceiling (CLAIMS.md units 50, 71): a paraphrased or semantically-hidden secret slips it, and it false-positived on benign base64 images in a real session. The gate is a best-effort rung that never load-bears — the floor is the capability lock, not this detector (the standing detector-is-not-the-floor thesis).

Triage decision

Action: close #552 as triaged → prior art cited + a real threat fak already gates at runtime (result-admit), with the ‘logged’ channel out of scope and the gate explicitly off the floor; the cross-language static analyzer is not adopted (this note). No code change in this increment: tools/idea_scout.py surfaced and scored the candidate correctly (topic mcp-security, score 57), and the right small artifact for a research / security triage is the recorded verdict + the named residuals, not a half-built static-analysis framework.

Next step (the smallest honest follow-on, if pursued): a one-time test asserting the result-admit gate screens an error / raised-exception tool-result payload identically to a success payload — closing the one residual the paper surfaces that touches fak’s own boundary (the “raised” implicit sink) — filed as its own scoped test against internal/ctxmmu. It guards the invariant this note names rather than importing the paper’s source-side detector-and-taint framework.