安全模型: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>。不換行空格顯示為 ⍽,行尾空白顯示為 ·,Tab 顯示為 »。

    所有不顯示任何內容的字元,都以同樣的方式顯示為洋紅色色塊上的 <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 指定了一個掛鉤(hook),git status 等 git 指令會呼叫它;過濾器驅動程式則指定了對檔案內容執行的程式。如果編輯器向 git 詢問一個剛解壓縮的儲存庫的狀態,就可能執行它們。[20] [21] [22]

    sim 的因應

    sim 會先向 git 詢問儲存庫的設定。命令列能擋住的都會被關閉(core.fsmonitor、hooks、過濾器、外部 diff、文字轉換),然後 git 照常回答。如果儲存庫自身的範圍裡還定義了其他可能執行指令的項目(core.sshCommand、可能引入這類項目的 include),就不執行 git。git 執行時不經過 shell,帶 --no-optional-locks,環境中也禁止任何擷取。sim 不執行 git 的任何寫入類指令,所以不會觸發 hooks。檔案樹會寫出 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)