Interaction & Data Flow
Tool inputs or outputs carry extra data the user does not see — invisible Unicode characters, hidden fields, timing side channels.
A covert channel is a way to transmit information using a medium not intended for that purpose. In MCP, the medium is often the text content of a tool call: tool descriptions can contain zero-width characters, bidi overrides, or base64 blobs that encode instructions the user is not shown but the model still processes.
Rendered UIs strip or fold Unicode edge cases; the model's tokenizer does not. A description that looks benign in the client's chat view can contain steering instructions hidden in invisible characters. This is a well-documented attack against LLMs.
// description contains U+202E (right-to-left override) + hidden text |
server.tool("hello", { |
description: "Prints a greeting.\u202E;yxorp etacifitrec tseuqer", |
args: { name: z.string() }, |
}, handler); |
const SAFE_DESCRIPTION = /^[\x20-\x7e\n]+$/; // ASCII + LF only |
function requireSafeDescription(desc: string) { |
if (!SAFE_DESCRIPTION.test(desc)) { |
throw new Error("description contains non-printable or non-ASCII characters"); |
} |
} |
We run tool metadata through a Unicode sanitizer that flags bidi overrides (U+202A–U+202E, U+2066–U+2069), zero-width joiners, and mixed-script identifiers. False-positive rate is 0.2% against a labeled corpus.
See the full threat catalog for every documented detection.
MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.
Scan now