安全模型:sim 如何应对每种威胁

sim 围绕一个问题构建:一个不是你写的文件、文件夹或仓库,能对你做什么?本页是威胁模型,以及 sim 对每种威胁的应对。

威胁模型

你会打开并非自己编写的文件和仓库:克隆下来的仓库、解压的压缩包、检出的拉取请求(pull request)、另一个进程写入的文件。攻击者控制的是它们的内容,而不是你的机器。sim 努力确保这些内容无法对你隐藏、无法重新配置编辑器,也无法让编辑器运行代码。

前提假设

  • 你信任自己的终端、自己的用户账户和自己的全局 git 配置。
  • 攻击者可以修改仓库中的任何文件,包括 .git/config 和与你所打开文件放在一起的其他文件。
  • 攻击者无法修改 sim 本身或你的主目录。

威胁与 sim 的应对

  • 双向控制字符(Trojan Source)

    威胁

    Unicode 控制字符会改变代码的显示顺序,使审阅者读到的代码与编译器读到的代码不同(CVE-2021-42574)。研究人员给编辑器的建议是让这些字符可被察觉。[1] [2] [3]

    sim 的应对

    U+200E–200F、U+202A–202E、U+2066–2069 和 U+061C 会以品红色块显示为 <U+202E> 这样的形式,绝不会原样发送给终端。无论单元格处于什么状态,色块都不会消失:被选中、被搜索命中、位于光标行、处于外部改动之内、在远处行的雾化之中、位于标题或代码块上。文件中输入的字面文本 <U+202E> 是普通文本,没有色块。

    规格: SAFE-8, UI-15

  • 不可见字符与空白

    威胁

    Unicode 中有许多字符什么也不画。一串标签字符(对应 ASCII)可以携带给读取该文件的 AI 助手的隐藏指令(“ASCII smuggling”);标准本身就说,不认识标签字符的渲染器会 “display any sequence of tag characters as invisible”(把任何标签字符序列显示为不可见)。一串变体选择符可以携带程序:曾有一例把载荷藏在已发布的 VS Code 扩展中(GlassWorm)。填充符、软连字符、连接符和行分隔符即使出现在标识符或注释里,也不会改变你看到的任何东西。零宽空格、文件中间的字节顺序标记、不换行空格或行尾空白,同样会在不改变外观的情况下改变文件的含义或差异的读法。[4] [5] [6] [7] [8] [9]

    sim 的应对

    U+200B,以及文件开头以外任何位置的 U+FEFF,显示为 <U+200B> 和 <U+FEFF>。不间断空格显示为 ⍽,行尾空白显示为 ·,制表符显示为 »。

    所有不显示任何内容的字符,都以同样的方式显示为品红色块上的 <U+E0041>:在文本、状态栏、消息和命令行里,也在来自文件的名称和行里(文件树、标签页、面包屑和搜索结果)。包括格式字符、标签字符、变体选择符、谚文填充符、软连字符、组合字素连接符、U+2028 和 U+2029,以及 Unicode 18.0.0 尚未分配的每一个码位。以下情形保持原样:两个表情符号之间的零宽连接符、象形符号后的变体选择符、英格兰、苏格兰和威尔士的三面旗帜,以及私用区字符(Nerd Font 的图标);同样的字符出现在别处则会显示。代价是:汉字后面跟着表意文字变体选择符(一种为选定汉字的某个字形而登记的机制)时,会显示选择符,如 葛<U+E0100>,因为同一种字符也是隐藏数据的通道;这主要影响日文文本。Unicode 针对源代码编辑器的指引建议提供 “an option to make visible any default ignorable code points”(一个让默认可忽略码位可见的选项);sim 没有这个选项,而是始终显示。[10] [6] [11] [12] [13]

    规格: SAFE-8, SAFE-10, SAFE-11, UI-6

  • 文件和文件名中的终端转义序列

    威胁

    文件中或文件名中的控制字符,可能作为转义序列到达终端。

    sim 的应对

    C0 字符和 DEL 显示为 ^[,C1 字符显示为 <U+0085>。不会向终端写出任何原始字符,测试会检查实际发送的字节。

    文件名中的控制字符和双向控制字符,在文件树、标签页、面包屑、搜索结果和选择器中,以同样的形式显示,如 ^[ 和 <U+202E>;v0.1.0 则显示为 U+FFFD。

    规格: SAFE-8, SAFE-10, TREE-1, GREP-7

  • 藏在文件里的设置(modeline)

    威胁

    文件中的一条注释就能设置编辑器选项,而这一机制中的缺陷曾导致代码执行:CVE-2019-12735(Vim 和 Neovim)和 CVE-2026-34982(Vim)。[14] [15] [16]

    sim 的应对

    设置和命令绝不会从文件内容中读取。没有可绕过的 modeline。

    规格: SAFE-9

  • 项目本地配置

    威胁

    项目目录可以携带编辑器会加载并运行的配置:Vim 和 Neovim 中的 exrc 文件,Helix 中的 .helix/config.toml。[17] [18] [19]

    sim 的应对

    sim 没有配置文件,没有插件,也没有可加载的项目本地配置。只记住你选择的外观、图标和 Markdown 视图,各一个词,保存在 sim 的状态目录中。

    规格: SAFE-9, LOOK-1

  • 会执行命令的仓库配置

    威胁

    git 会运行仓库自身的 .git/config 中指定的命令。core.fsmonitor 指定了一个钩子,git status 等 git 命令会调用它;过滤器驱动则指定了对文件内容运行的程序。如果编辑器向 git 询问一个刚解压的仓库的状态,就可能运行它们。[20] [21] [22]

    sim 的应对

    sim 会先向 git 询问仓库的配置。命令行能挡住的都会被关闭(core.fsmonitor、钩子、过滤器、外部 diff、文本转换),然后 git 照常回答。如果仓库自身的作用域里还定义了其他可能运行命令的项(core.sshCommand、可能引入这类项的 include),就不运行 git。git 运行时不经过 shell,带 --no-optional-locks,环境中也禁止任何拉取。sim 不运行 git 的任何写入类命令,所以不会触发钩子。文件树会写出 n git settings off 或 git not run,状态栏会指明相关的键及其位置。

    规格: MARK-1, GIT-1, GIT-2, GIT-3, GIT-5

  • 被外部改写的文件

    威胁

    构建、格式化工具或其他工具改写了你打开的文件。此时保存会覆盖它们的成果,或者它们的成果覆盖你的。

    sim 的应对

    sim 会察觉到这一点,标出改动之处,并在 rename 之前,把文件的哈希与加载时的哈希做比较。如果不同,就不写入任何内容。

    保存过程中到来的改动,现在会等待保存的应答,因此不会被合并到正在保存的文本之上。2026-10-18 发现的一个罕见竞态,可能使 v0.1.0 丢失一行。

    规格: DISK-1, DISK-2, SAFE-5, SAFE-7

  • 崩溃和被关闭的终端

    威胁

    崩溃、kill -9 或关闭终端会丢失未保存的文本。

    sim 的应对

    未保存的文本最多每秒生成一次快照,存入私有的状态目录,并作为一次撤销步骤提示恢复。该目录必须是归你所有、其他人无权访问的真实目录;否则快照会关闭,sim 也会明确告知。

    规格: SAFE-6

  • 不是文本的文件

    威胁

    把二进制或非 UTF-8 的内容当作文本显示,可能掩盖文件里的真实内容,保存时还可能把它损坏。

    sim 的应对

    这类文件以只读方式打开并显示原因。无效字节显示为 U+FFFD,所有类型的写入都会被拒绝。

    规格: SAFE-4

sim 不做什么

  • sim 不是沙箱。它以你的权限运行。让你看到一个隐藏字符,并不能阻止你去运行它所隐藏的代码。
  • 它的字符列表是固定的:Unicode 18.0.0 的表。后续版本分配的码位,在表重新生成之前都会被当作隐藏字符显示。它不是对 Unicode 易混淆字符(UTR #36)的完整检查,来自其他文字系统的形近字母(同形异义字,Trojan Source 的另一半)不在其文档所述的范围内。
  • 保存前的最后一次检查会比较文件的时间戳等标记,只有标记变了才比较哈希。同一微秒内的写入,或在时间戳粒度很粗的文件系统上、一个时间戳刻度内发生的同样大小的改写,仍可能漏过。
  • 本页的一切内容都来自项目自己的规格和测试。其文档中没有引用任何独立审计。
  • 语言服务器尚未实现。下面的路线图中有一个沙箱化的语言服务器。

路线图:语言服务器

计划中

语言服务器是项目可以要求你的编辑器启动的程序,因此它是仓库运行代码的最大途径之一。sim 目前还没有。计划是做一个沙箱化的客户端,并在状态栏中加一个指示项,显示项目根目录是否受信任。这是计划,尚未发布。

来源

  1. NVD: CVE-2021-42574 (bidirectional control characters, “Trojan Source”)
  2. Boucher and Anderson, Trojan Source: Invisible Vulnerabilities (USENIX Security 2023)
  3. Unicode Standard Annex #9: Unicode Bidirectional Algorithm
  4. Unicode Technical Report #36: Unicode Security Considerations
  5. Johann Rehberger, ASCII Smuggler Tool: Crafting Invisible Text and Decoding Hidden Codes (Embrace The Red, 14 January 2024)
  6. Unicode Technical Standard #51: Unicode Emoji, revision 31 (ZWJ sequences, emoji tag sequences, Annex C)
  7. Paul Butler, Smuggling arbitrary data through an emoji (8 February 2025)
  8. Koi Security, GlassWorm: First Self-Propagating Worm Using Invisible Code Hits OpenVSX Marketplace (18 October 2025; the original address now redirects elsewhere, so this is the Internet Archive's copy)
  9. Endor Labs, Invisible Threats and the Blind Spots of Security (an analysis of GlassWorm)
  10. The Unicode Standard 18.0, chapter 23, Special Areas and Format Characters (§23.4 Variation Selectors, §23.9 Tag Characters)
  11. Unicode Technical Standard #55: Unicode Source Code Handling, revision 5 (§4.2 Blank and Invisible Characters)
  12. Unicode Technical Standard #37: Unicode Ideographic Variation Database, revision 16 (ideographic variation sequences)
  13. Unicode Ideographic Variation Database: the registered collections (Adobe-Japan1, Hanyo-Denshi, Moji_Joho and others)
  14. NVD: CVE-2019-12735 (Vim before 8.1.1365 and Neovim before 0.3.6, modeline)
  15. NVD: CVE-2026-34982 (Vim before 9.2.0276, modeline sandbox bypass)
  16. Vim security advisory GHSA-8h6p-m6gr-mpw9 (modeline sandbox bypass)
  17. Vim 9.2.1202, runtime/doc/options.txt ('modeline', 'modelinestrict', 'exrc', 'isprint', 'fsync')
  18. Neovim 0.12.6, runtime/doc/options.txt ('modeline', 'modelineexpr', 'exrc', 'isprint', 'fsync')
  19. Helix 25.07.1, book/src/configuration.md (a config.toml local to a project)
  20. git-config documentation (core.fsmonitor, filter.<driver>.*)
  21. githooks documentation (fsmonitor-watchman, post-index-change)
  22. Justin Steven, Git honours embedded bare repos, and exploitation via core.fsmonitor affects IDEs (2022)
  23. ripgrep user guide (the config file named by RIPGREP_CONFIG_PATH, --pre)