Interaction & Data Flow
Tool output contains ANSI control sequences (`\x1b[...`) that re-colour, clear the screen, or remap keys when the client renders output to a terminal — used to hide instructions or spoof authoritative UI.
ANSI escape codes are in-band control signals the terminal interprets — cursor movement, colour, screen clearing, and even keyboard remapping (some terminals). When tool output is rendered in a TTY-like view (Claude Code, terminal-based MCP clients), an escape sequence embedded in the response can rewrite what the user sees, hide adjacent tool output, or overwrite a prompt to mislead the next keystroke.
Many MCP clients render tool output to terminals. A tool that forwards attacker-supplied text (from a webpage, file, or API response) can smuggle in escape sequences the user never notices. The defence is simple: strip or escape control characters before returning.
@server.tool() |
def show_log(log_text: str) -> str: |
# Attacker-controlled log line can contain \x1b[2J (clear screen) |
# or reposition the cursor to hide other tool output. |
return log_text |
import re |
_CTRL = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\x1b]") |
@server.tool() |
def show_log(log_text: str) -> str: |
return _CTRL.sub("", log_text) |
We flag tool-handler return paths that emit strings containing literal ANSI escape patterns (`\x1b[`, `\033[`, `\u001b[`) or that pass through external content without a control-character stripper.
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