ANSI 转义序列注入(ANSI escape sequence injection),是指把终端控制指令混进本该只是“纯文本”的数据里,让终端在显示时执行这些指令,从而伪造、隐藏或篡改你最终看到的内容。
终端从来不只是文本框
早期电传打字机(Teletype)用同一条数据流同时传两类信息:要打印的字,以及控制动作(响铃、回车、换行)。终端模拟器(terminal emulator)继承了这个设计:以 ESC(字节 0x1B)开头的约定字符就是一条命令。ESC[31m 把字变红,ESC[2J 清屏,ESC[H 把光标挪回左上角,ESC[K 擦掉当前行,ESC]0;标题 改窗口标题。这类控制序列统称 ANSI 转义序列,名字来自早期 ANSI 标准,今天的终端几乎都支持。
问题在于:终端分不清这些字节是“程序有意输出的界面控制”,还是“从文件、日志、网络里读来的数据”。
打个比方:就像打印一份文件时,几行内容其实是写给打印机的控制码,并非给你看的文字。你读到“一切正常”,打印机却照着控制码把后面几行涂白,或把光标移回去重打一遍。
具体长什么样
如果一段输出里带 \r\033[K,\r 会把光标送回行首,\033[K 擦掉整行,接着打印的字就盖掉了上一行原本的内容。你对着日志文件 cat 一下,屏幕上最后留下的是干干净净的“0 errors”,真正那几行报错被压在下面看不见。文件本身没被改动,是显示环节骗了你。同理,彩色的“成功”字样、伪造的提示符、假装成另一个程序输出的表格,都能这么造出来。
和相邻概念的区别
| 概念 | 被当成“代码”的数据 | 谁在解释 | 典型后果 |
|---|---|---|---|
| ANSI 转义序列注入 | 终端控制序列 | 终端模拟器、渲染器 | 屏幕内容被覆盖、伪造、隐藏 |
| CRLF 注入 | 换行符 | 日志解析器 | 一条记录被拆成两条,凭空多出日志行 |
| XSS | HTML、JavaScript | 浏览器 | 在别人页面里执行脚本 |
| 提示注入(prompt injection) | 自然语言指令 | 大模型 | 模型偏离原任务 |
关键差别:ANSI 注入通常不改变文件本身。日志是“忠实”的,出问题的是渲染层,所以 grep 原文件、做 diff 往往看不出异常,肉眼盯屏幕反而会被骗。
对从业者意味着什么
- 别对来路不明的文件裸
cat。cat -v会把不可打印字符显示成^[一类,less默认也不解释这些序列;在 CI 里汇总外部输出前,先剥掉或转义控制字符。 - 智能体的工具返回值同样要清洗。Agent 把命令的 stdout、stderr 直接塞回上下文,如果下游有人看渲染后的终端,或有组件会解释这些字节,一条被污染的输出就能同时骗人和骗流程。稳妥做法是工具层统一 sanitize:把不可打印字符转成可见形式,或只取结构化字段。
- 终端本身也别全信。某些序列能写剪贴板(OSC 52)、改标题、查询终端状态,各家支持范围和默认开关不同,以官方文档为准,这也是不少终端默认关掉这类能力的原因。
一句话收尾:凡是“给人看的字节流”,都应当作不可信输入处理,控制字符也不例外。
