Workspace trust
Helix has several features that can execute arbitrary code:
- Language servers (LSP)
- Debug adapters (DAP)
- Local workspace configuration (
.helix/config.toml,.helix/languages.toml) - Git integration (filters and other commands in a repository’s
.git/config)
To protect against malicious projects (a checked-out PR, a freshly cloned
repository, etc.) Helix gates these behind explicit per-workspace trust.
By default language servers start automatically (their binaries come from
$PATH, not from the workspace) and debug adapters may be launched, but
loading .helix/config.toml or .helix/languages.toml and trusting a
repository’s .git/config requires opting in. Note that debug adapters
are never started automatically — you launch them yourself — but the same
trust level still gates whether they may run. The model is intentionally
similar to direnv: you run :workspace-trust once
per workspace and Helix remembers across sessions.
Granting trust
When Helix opens a file inside a workspace it has never seen before, a modal trust prompt asks:
- Trust — allow the workspace permanently.
- Never — exclude the workspace; never prompt again.
<Esc> (or any other dismissal) caches “untrusted for this session” so
the prompt doesn’t re-fire for every file you open in the workspace. The
next time you start Helix in that workspace, it’ll prompt again.
A small [⚠] indicator appears in the bottom-right of the editor (next
to the macro-recording [@]) whenever the workspace is in restricted mode
and running :workspace-trust would change observable behavior — i.e.
when there’s a local config to load or an LSP that would start.
You can also run :workspace-trust / :workspace-untrust /
:workspace-exclude directly from the typed command prompt.
Revoking trust
Run :workspace-untrust to revoke a workspace’s trust grant. The next time
you open a file in that workspace, you’re back to the untrusted hint.
Detecting changes after trust was granted
When you trust a workspace, Helix records a hash of every file under
.helix/. If those files change afterwards (a malicious checkout, an
inadvertent rebase, etc.) Helix detects the mismatch on the next open and
reports the workspace as stale:
Workspace `.helix/` config changed since `:workspace-trust`. Local config
not loaded. Run `:workspace-trust` to re-allow.
In the stale state, language servers continue to run (they use the
globally-configured binaries on $PATH, which are unchanged), but
.helix/config.toml and .helix/languages.toml are not loaded. Run
:workspace-trust again to re-pin the new hash.
Storage
Trust grants live in data_dir()/workspace_trust/, one small file per
workspace. The filename is the SHA-256 of the workspace’s absolute path;
the contents look like:
path = /home/user/proj1
hash = sha256:abc123...
excluded = false
- Linux, macOS:
~/.local/share/helix/workspace_trust/ - Windows:
%AppData%\Roaming\helix\workspace_trust\
The one-file-per-workspace shape is safe under multiple concurrent Helix instances — different workspaces never write the same file.
Configuration
Settings live under [editor.workspace-trust]:
| Key | Values | Default | Effect |
|---|---|---|---|
level | "none", "servers", "insecure" | "servers" | What is auto-trusted in every workspace. See below. |
prompt | true, false | true | Whether to surface the modal popup. The [⚠] indicator is shown regardless. |
trusted | list of glob patterns | [] | Workspaces matching a pattern are trusted without a grant. Discouraged; see below. |
Recommended setups
Default: trust servers, prompt before loading workspace config.
[editor.workspace-trust]
level = "servers"
prompt = true
Language servers start automatically in every workspace — their binaries
come from $PATH and are not workspace-controlled — and debug adapters
you launch are allowed to run. The modal only appears when opening a file
in a workspace whose .helix/config.toml or .helix/languages.toml would
unlock something. Trust everything else with one keystroke per workspace,
deny with another.
Maximum security: never prompt, trust each workspace by hand.
[editor.workspace-trust]
level = "none"
prompt = false
Nothing trusts implicitly: language servers, debug adapters, local
config, and git Trust::Full are all off until you run
:workspace-trust. The popup never appears; the [⚠] indicator in the
bottom-right is your only signal that the current workspace is
restricted. Suited to users who would rather grant trust as a
deliberate action than dismiss a dialog.
Warning
level = "insecure"is highly discouraged. It implicitly trusts every workspace you open, which defeats the protection entirely: a checked-out PR with a malicious.helix/config.tomlwould get its configuration loaded and any language server it defines launched, with no prompt and no indicator. Only set this if you accept full responsibility for what’s in every project directory youcdinto.
Trusting workspaces by path (discouraged)
If you keep all your repositories under a predictable layout, you can trust them in bulk with glob patterns instead of granting each workspace individually:
[editor.workspace-trust]
trusted = [
"~/src/github.com/me/*",
"~/work/repos/*",
]
A workspace whose path matches a pattern is trusted for everything, just
as if you had run :workspace-trust in it. ~ and environment variables
are expanded.
Warning
This is weaker than an explicit grant and is discouraged. It skips the
.helix/change detection entirely (a malicious checkout under a matched directory is never flagged as stale), and it trusts any repository that later lands under a matching path — including one you clone into~/src/github.com/me/from an untrusted source. Prefer granting trust per workspace; reach for this only if the prompts are genuinely disruptive to your workflow. An explicit:workspace-excludestill overrides a matching pattern.
Git trust
Workspace trust also gates how Helix opens git repositories. Untrusted
workspaces are opened in gix’s
Trust::Reduced mode; trusted workspaces use Trust::Full.
Under Trust::Reduced, gix still runs the full filter pipeline (so
built-in conversions like core.autocrlf keep working) but ignores
configuration coming from the untrusted, repository-local .git/config.
That means filter.*.clean / filter.*.smudge drivers and similar
keys that would otherwise execute external programs are dropped until you
trust the workspace.
Helix forces this trust level explicitly rather than letting gix infer it
from .git directory ownership — a malicious .git/config in a directory
you happen to own is still treated as untrusted until you run
:workspace-trust.