Security model: what sim does about each threat
sim is built around one question: what does a file, a folder or a repository you did not write get to do to you? This page is the threat model, and what sim does about each threat.
Threat model
You open files and repositories you did not write: a clone, an unpacked archive, a pull request checkout, a file another process writes. The attacker controls their content, not your machine. sim tries to make sure that content cannot hide from you, cannot reconfigure the editor, and cannot make the editor run code.
Assumptions
- You trust your own terminal, your own user account and your own global git configuration.
- The attacker can change any file in a repository, including .git/config and the files that sit next to the one you open.
- The attacker cannot change sim itself or your home directory.
Threats and what sim does
Bidirectional control characters (Trojan Source)
The threat
Unicode controls reorder how code is displayed, so the code a reviewer reads is not the code a compiler reads (CVE-2021-42574). The researchers' advice to editors is to make these characters perceptible.[1] [2] [3]
What sim does
U+200E–200F, U+202A–202E, U+2066–2069 and U+061C are drawn as
<U+202E>on a magenta block and are never sent raw to the terminal. The block holds in every state a cell can be in: selected, matched by a search, on the cursor line, inside a change from outside, in the fog of a far row, on a heading or a code block. The literal text<U+202E>typed in a file is ordinary text and gets no block.Spec: SAFE-8, UI-15
Invisible characters and blanks
The threat
Many Unicode characters draw nothing at all. A run of tag characters, which mirror ASCII, can carry a hidden instruction to an AI assistant that reads the file (“ASCII smuggling”); a tag-unaware renderer will “display any sequence of tag characters as invisible”. A run of variation selectors can carry a program: one hid a payload in published VS Code extensions (GlassWorm). Fillers, soft hyphens, joiners and line separators can sit inside an identifier or a comment and change nothing you can see. A zero-width space, a byte-order mark in the middle of a file, a no-break space or trailing blanks change what a file means, or how a diff reads, in the same way.[4] [5] [6] [7] [8] [9]
What sim does
U+200B, and U+FEFF anywhere but the start of the file, are drawn as
<U+200B>and<U+FEFF>. A no-break space is drawn as⍽, trailing blanks as·and tabs as».Every character that draws nothing is shown the same way, as
<U+E0041>on the magenta block, in the text, the status line, messages and the command line, and in the names and lines that come from files (the tree, tabs, breadcrumb and search results): format characters, tag characters, variation selectors, Hangul fillers, the soft hyphen, the combining grapheme joiner, U+2028 and U+2029, and every code point that Unicode 18.0.0 leaves unassigned. These stay as they are: a zero-width joiner between two emoji, a variation selector after a pictograph, the three flags of England, Scotland and Wales, and private-use characters (the icons of a Nerd Font); the same characters anywhere else are shown. The cost: a kanji followed by an ideographic variation selector (a registered way to pick one glyph form of a kanji) shows the selector,葛<U+E0100>, because the same character is a channel that hides data; this falls mostly on Japanese text. Unicode's guidance for source-code editors recommends “an option to make visible any default ignorable code points”; sim has no such option, and always shows them.[10] [6] [11] [12] [13]Spec: SAFE-8, SAFE-10, SAFE-11, UI-6
Terminal escape sequences in files and file names
The threat
Control characters in a file, or in a file name, can reach the terminal as escape sequences.
What sim does
C0 characters and DEL are drawn as
^[and C1 characters as<U+0085>. Nothing raw is written to the terminal, and tests check the bytes sent.Control and bidirectional characters in file names are drawn in the same forms,
^[and<U+202E>, in the tree, the tabs, the breadcrumb, search results and the picker; v0.1.0 drew them as U+FFFD.Spec: SAFE-8, SAFE-10, TREE-1, GREP-7
Settings hidden in a file (modelines)
The threat
A comment in a file can set editor options, and bugs in that mechanism have led to code execution: CVE-2019-12735 (Vim and Neovim) and CVE-2026-34982 (Vim).[14] [15] [16]
What sim does
Settings and commands are never read from file contents. There is no modeline to bypass.
Spec: SAFE-9
Project-local configuration
The threat
A project directory can carry configuration that an editor loads and runs:
exrcfiles in Vim and Neovim,.helix/config.tomlin Helix.[17] [18] [19]What sim does
sim has no config files, no plugins and no project-local configuration to load. Only your choice of look, icons and Markdown view is remembered, as one word each, in sim's state directory.
Spec: SAFE-9, LOOK-1
Repository config that runs commands
The threat
git runs commands named in a repository's own
.git/config.core.fsmonitornames a hook that git commands such asgit statusinvoke, and a filter driver names programs that run on a file's content. An editor that asks git for the status of a repository you just unpacked can run them.[20] [21] [22]What sim does
sim asks git for the repository's config first. What a command line can stop is turned off (
core.fsmonitor, hooks, filters, an external diff, a text conversion), and git answers. If the repository's own scopes define anything else that can hold a command (core.sshCommand, an include that could bring one in), git is not run. git then runs without a shell, with--no-optional-locks, and with an environment that stops any fetch. sim runs none of git's writing commands, so no hook runs. The tree saysn git settings offorgit not run, and the status line names the key and where it is.Spec: MARK-1, GIT-1, GIT-2, GIT-3, GIT-5
Search that runs the repository's code
The threat
ripgrep takes extra flags from a config file named in the environment and can run a command on every file it reads (
--pre).[23]What sim does
sim finds ripgrep in the absolute entries of
PATH, runs it by full path with an empty environment and--no-config, and never gives it--pre. The query and the files come after-eand--, so none of them is an option.Spec: GREP-7, GREP-8
Links that lead out of the project
The threat
A symlink can point outside the project, and a shared directory can hold a link planted for a save to follow.
What sim does
Search and preview read only regular files whose real path is below the project root. A save refuses to write through a link that neither you nor root owns, in any component of the path.
Spec: SAFE-1, GREP-7
Files rewritten from outside
The threat
A build, a formatter or a tool rewrites the file you have open. Saving then overwrites its work, or its work overwrites yours.
What sim does
sim notices, marks what changed, and compares the file's hash with the one at load right before the rename. If they differ, nothing is written.
A change that arrives while a save is being written now waits for the save's answer, so it cannot be merged over the text being saved. A rare race found on 2026-10-18 could lose a line in v0.1.0.
Spec: DISK-1, DISK-2, SAFE-5, SAFE-7
Crashes and closed terminals
The threat
A crash,
kill -9or a closed terminal loses unsaved text.What sim does
Unsaved text is snapshotted at most once per second into a private state directory, and offered back as one undo step. The directory must be a real directory owned by you with no access for others; otherwise snapshots are off and sim says so.
Spec: SAFE-6
Files that are not text
The threat
Binary or non-UTF-8 content, shown as if it were text, can hide what a file holds and be corrupted by a save.
What sim does
Such files open read-only with the reason shown. Invalid bytes are drawn as U+FFFD, and every kind of write is refused.
Spec: SAFE-4
What sim does not do
- sim is not a sandbox. It runs with your privileges. Showing you a hidden character does not stop you from running the code it hides.
- Its list of characters is fixed: the table of Unicode 18.0.0. A code point that a later version assigns is shown as hidden until the table is made again. It is not a full check of Unicode confusables (UTR #36), and look-alike letters from other scripts (homoglyphs, the other half of Trojan Source) are not part of what its docs describe.
- The last check before a save compares the file's stamp, and its hash only if the stamp moved. A write in the same microsecond, or a same-size rewrite within one timestamp tick of a file system with coarse timestamps, can still slip through.
- Everything on this page comes from the project's own specification and tests. No independent audit is cited in its docs.
- Language servers are not built yet. A sandboxed one is on the roadmap below.
Roadmap: language servers
Planned
A language server is a program a project can ask your editor to start, so it is one of the biggest ways a repository can run code. sim does not have one yet. The plan is a sandboxed client and a status-line indicator of whether the project root is trusted. It is planned, not shipped.
Sources
- NVD: CVE-2021-42574 (bidirectional control characters, “Trojan Source”)
- Boucher and Anderson, Trojan Source: Invisible Vulnerabilities (USENIX Security 2023)
- Unicode Standard Annex #9: Unicode Bidirectional Algorithm
- Unicode Technical Report #36: Unicode Security Considerations
- Johann Rehberger, ASCII Smuggler Tool: Crafting Invisible Text and Decoding Hidden Codes (Embrace The Red, 14 January 2024)
- Unicode Technical Standard #51: Unicode Emoji, revision 31 (ZWJ sequences, emoji tag sequences, Annex C)
- Paul Butler, Smuggling arbitrary data through an emoji (8 February 2025)
- 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)
- Endor Labs, Invisible Threats and the Blind Spots of Security (an analysis of GlassWorm)
- The Unicode Standard 18.0, chapter 23, Special Areas and Format Characters (§23.4 Variation Selectors, §23.9 Tag Characters)
- Unicode Technical Standard #55: Unicode Source Code Handling, revision 5 (§4.2 Blank and Invisible Characters)
- Unicode Technical Standard #37: Unicode Ideographic Variation Database, revision 16 (ideographic variation sequences)
- Unicode Ideographic Variation Database: the registered collections (Adobe-Japan1, Hanyo-Denshi, Moji_Joho and others)
- NVD: CVE-2019-12735 (Vim before 8.1.1365 and Neovim before 0.3.6, modeline)
- NVD: CVE-2026-34982 (Vim before 9.2.0276, modeline sandbox bypass)
- Vim security advisory GHSA-8h6p-m6gr-mpw9 (modeline sandbox bypass)
- Vim 9.2.1202, runtime/doc/options.txt ('modeline', 'modelinestrict', 'exrc', 'isprint', 'fsync')
- Neovim 0.12.6, runtime/doc/options.txt ('modeline', 'modelineexpr', 'exrc', 'isprint', 'fsync')
- Helix 25.07.1, book/src/configuration.md (a config.toml local to a project)
- git-config documentation (core.fsmonitor, filter.<driver>.*)
- githooks documentation (fsmonitor-watchman, post-index-change)
- Justin Steven, Git honours embedded bare repos, and exploitation via core.fsmonitor affects IDEs (2022)
- ripgrep user guide (the config file named by RIPGREP_CONFIG_PATH, --pre)