security: require trust check for .tool-versions Tera templates#8675
security: require trust check for .tool-versions Tera templates#8675
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request resolves a security vulnerability in how mise handles Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a critical security fix by adding a trust check for .tool-versions files that contain Tera template syntax. This prevents potential arbitrary command execution from untrusted repositories. The change correctly identifies templated files and gates them behind the existing trust_check mechanism, while leaving plain .tool-versions files unaffected. A new end-to-end test is added to validate the fix, covering scenarios for untrusted, trusted, and non-templated files. My review includes a suggestion to improve the robustness of the new test script.
| #!/usr/bin/env bash | ||
|
|
||
| # Test that .tool-versions files with Tera templates require trust verification | ||
| # This prevents silent arbitrary code execution from untrusted .tool-versions files | ||
|
|
There was a problem hiding this comment.
For improved test robustness, it's a good practice to use trap to ensure cleanup of temporary files, even if the script exits unexpectedly. This avoids leaving artifacts in /tmp.
With this change, you can also remove the explicit rm calls on lines 19 and 32.
#!/usr/bin/env bash
trap 'rm -f /tmp/mise-trust-test-marker' EXIT
# Test that .tool-versions files with Tera templates require trust verification
# This prevents silent arbitrary code execution from untrusted .tool-versions files
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| let mut cf = Self::init(&path); | ||
| let dir = path.parent(); | ||
| let s = get_tera(dir).render_str(s, &cf.context)?; | ||
| let s = if s.contains("{{") || s.contains("{%") || s.contains("{#") { |
There was a problem hiding this comment.
Duplicated security-critical template detection logic across files
Low Severity
The template syntax detection check (s.contains("{{") || s.contains("{%") || s.contains("{#")) duplicates the logic in MiseToml::contains_template_syntax. Since this check is a security gate controlling whether trust verification occurs, having it duplicated in two files risks future inconsistency if one is updated but not the other. A shared utility function would be more maintainable.
Greptile SummaryThis PR patches a security vulnerability where Key changes:
The fix integrates cleanly with the existing trust infrastructure: in paranoid mode Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[parse_str called] --> B{Template syntax\ndetected in file?}
B -- No --> C[Use plain string as-is]
B -- Yes --> D[trust_check called on path]
D --> E{Is path trusted?}
E -- Yes --> F[Tera render_str\nexec runs here]
E -- No, paranoid mode --> G{File hash\nmatches stored hash?}
G -- Yes --> F
G -- No --> H[Return Err UntrustedConfig]
E -- No, CI auto-trust --> F
E -- No, interactive --> I{Prompt user:\ntrust this config?}
I -- Yes --> J[Store trust marker] --> F
I -- No --> H
F --> K[Parse rendered output into toolset]
C --> K
Last reviewed commit: "fix(test): use MISE_..." |
.tool-versions files were processed through Tera's render_str() with
the exec() function registered, allowing arbitrary command execution
without any trust verification. Unlike .mise.toml files which call
trust_check() before parsing, .tool-versions bypassed this entirely.
This meant a malicious .tool-versions file in a cloned repository could
silently execute code when a user with mise shell activation entered the
directory — no trust prompt, no warning.
Add trust_check() gating to .tool-versions parsing when template syntax
({{, {%, {#) is detected. Plain .tool-versions files without templates
continue to work without requiring trust.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address review feedback: is_trusted() auto-trusts in CI via ci_info::is_ci(), which would bypass the trust gate under test. MISE_PARANOID=1 forces hash-based trust checking. Also fix the trusted template sub-test to properly validate template rendering. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0fc93fa to
19b1e16
Compare
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.9 x -- echo |
25.9 ± 0.4 | 25.1 | 30.5 | 1.00 |
mise x -- echo |
26.0 ± 0.4 | 24.8 | 28.4 | 1.00 ± 0.02 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.9 env |
25.4 ± 0.8 | 24.3 | 32.0 | 1.00 |
mise env |
25.7 ± 0.8 | 24.4 | 38.0 | 1.01 ± 0.05 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.9 hook-env |
26.0 ± 0.4 | 25.1 | 27.7 | 1.00 |
mise hook-env |
26.2 ± 0.4 | 25.2 | 28.0 | 1.01 ± 0.02 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.9 ls |
25.2 ± 0.7 | 24.0 | 32.6 | 1.00 |
mise ls |
25.3 ± 0.5 | 24.3 | 29.8 | 1.01 ± 0.04 |
xtasks/test/perf
| Command | mise-2026.3.9 | mise | Variance |
|---|---|---|---|
| install (cached) | 157ms | 156ms | +0% |
| ls (cached) | 87ms | 86ms | +1% |
| bin-paths (cached) | 89ms | 89ms | +0% |
| task-ls (cached) | 867ms | 842ms | +2% |
PR jdx#8675 added trust checks for .tool-versions files containing Tera templates, but the error path in task_list.rs still checks trust on all config files regardless of type or content. This causes plain .tool-versions files (no templates) to trigger trust errors. Skip trust verification for .tool-versions files that don't contain template syntax ({{, {%, {#}), consistent with the parsing logic.
PR jdx#8675 added trust checks for .tool-versions files containing Tera templates, but the error path in task_list.rs still checks trust on all config files regardless of type or content. This causes plain .tool-versions files (no templates) to trigger trust errors. Skip trust verification for .tool-versions files that don't contain template syntax ({{, {%, {#}), consistent with the parsing logic.
## Summary PR #8675 added trust gating for `.tool-versions` files containing Tera template syntax, but `task_list.rs` still calls `is_trusted()` on **all** config files when checking for untrusted configs. This causes plain `.tool-versions` files (just tool names and versions, no templates) to trigger trust errors like: ``` mise ERROR Config file(s) in ~/dev/myproject are not trusted: ~/dev/myproject/.tool-versions Trust them with `mise trust`. ``` This skips the trust check for `.tool-versions` files that don't contain template syntax (`{{`, `{%`, `{#`), consistent with the parsing logic added in #8675. ## Changes - `src/task/task_list.rs`: Added `is_plain_tool_versions()` helper that checks if a path is a `.tool-versions` file without Tera template markers. The `err_no_task` trust check now skips these files since they can't define tasks or execute code. ## Test plan - [ ] Plain `.tool-versions` (e.g. `ruby 3.3.3\nnodejs 14.21.3`) no longer triggers trust error - [ ] `.tool-versions` with template syntax (e.g. `nodejs {{ exec("echo 20") }}`) still requires trust - [ ] `.mise.toml` trust behavior unchanged --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>


Summary
.tool-versionsfiles were processed through Tera'srender_str()with theexec()function registered, allowing arbitrary command execution without any trust verification.mise.tomlfiles which calltrust_check()before parsing,.tool-versionsbypassed this entirely.tool-versionsin a cloned repo could silently execute code when a user with mise shell activationcd'd into the directory — no trust prompt, no warningtrust_check()gating when template syntax ({{,{%,{#) is detected in.tool-versionsfiles.tool-versionsfiles without templates continue to work without requiring trustTest plan
test_tool_versions_trust_checkvalidates:.tool-versionswithexec()template is blocked with trust errorexec()command does not run (no side effects).tool-versionswithout templates works without trust.tool-versionswith templates works aftermise trust🤖 Generated with Claude Code
Note
Medium Risk
Adds a new trust gate on
.tool-versionsparsing when template syntax is present, affecting config loading behavior and potentially breaking existing templated files until trusted; however the change is narrowly scoped and covered by an e2e test.Overview
Prevents arbitrary command execution via Tera templating in untrusted
.tool-versionsfiles by only runningrender_str()aftertrust_check()when template markers ({{,{%,{#) are detected; non-templated.tool-versionscontinue to parse without trust.Adds an e2e regression test that verifies untrusted templated
.tool-versionsare blocked without side effects, and that trusted templated and plain files still work. Also allowssecurityas a valid PR title type insemantic-pr-lint.Written by Cursor Bugbot for commit 19b1e16. This will update automatically on new commits. Configure here.