github jdx/mise v2026.10.13
v2026.10.13: Untrusted project configs can no longer change settings

3 hours ago

mise now ignores [settings] in a project config until you trust it. This release also adds per-version-range backend options to the registry and template support for command wrappers and [bootstrap.repos]. It fixes several bugs in lockfiles, tasks and multi-version tool options.

Security

  • [settings] from untrusted project configs is ignored. Before, a cloned repo's mise.toml could change settings as soon as mise found it, with no trust prompt. That included settings that redirect downloads or feed build commands, such as node.mirror_url, python.pyenv_repo and ruby.precompiled_url. These settings now apply only after mise trust, like [env], [hooks] and [tools] options already did. Trusted projects, global and system config, environment variables and CLI flags work as before. Commands that trust the active config implicitly (mise run, mise exec, mise install) reload settings after trusting it, so the project's settings still apply to that same command. Settings files are now parsed once per load. #14538, #14553 (@jdx)

    For example, if an untrusted repo sets [settings.python] pyenv_repo to its own URL, mise settings get python.pyenv_repo returns the default pyenv repository until you run mise trust.

  • mise's own zip dependency moved to 9.x, which fixes GHSA-4684-h2q9-2vcp. Older versions applied Unix permissions through extracted symlinks without checking that the target stayed inside the destination. mise uses this code to extract downloaded .zip tool archives. #14577 (@jdx)

Added

  • One registry backend can carry different options for each version range. A registry entry can list the same backend more than once, each time with its own min_version/max_version and options. Tools whose release assets changed at some version can then stay on one backend. Two entries can't give the same version different options unless their platforms don't overlap. Table syntax such as tool = { version = "1.4.0" } now takes its registry defaults from the entry that version selects. Older mise releases apply only the first entry's options to every version. #14543 (@jdx)

    backends = [
      { full = "github:example/tool", min_version = "2.0.0", options = { asset_pattern = "tool-v2-*" } },
      { full = "github:example/tool", max_version = "2.0.0", options = { asset_pattern = "tool-*" } },
    ]
  • mise ls-remote lists every version range of a registry tool. When a tool's backends serve different version ranges, mise now lists each range from the backend that serves it. Before, it listed only the first backend's range. For example, mise ls-remote hk now starts at 0.1.4 instead of 1.58.1. Explicit backends, overrides, --all and --strict-metadata behave as before. #14544 (@jdx)

  • Command wrapper values render as templates. command, args and env in [wrappers] can use vars, env and the usual template functions. tools and config_root are not available. A command that renders blank is an error. Use {% raw %} to keep literal braces, such as Docker's {{.Names}}. #14565 (@jdx)

    [wrappers.foo]
    command = "foo-real"
    args = ["--mode={{ vars.mode }}"]
    env = { FOO_HOME = "{{ [xdg_data_home, 'foo'] | join_path }}" }
  • [bootstrap.repos] supports templated url/ref and clone options. url and ref render from [vars] or the process environment. Values from a config's [env] table are not available. filter, depth and submodules = true are passed to the first git clone as --filter, --depth and --recurse-submodules. Existing checkouts are left as they are. depth can't be combined with a commit SHA or a refs/… ref. #14548 (@jdx, @ovidiubuligan)

    [bootstrap.repos]
    "~/src/large" = { url = "git@github.com:example/large.git", ref = "{{ vars.branch }}", filter = "blob:none", depth = 1 }
  • {{ system_brew_prefix }} template variable. It resolves to the Homebrew prefix that mise bootstrap installs into: /opt/homebrew on macOS and /home/linuxbrew/.linuxbrew on Linux, or the value of MISE_SYSTEM_BREW_PREFIX. It does not detect a Homebrew install somewhere else. [bootstrap.user].login_shell now renders templates too, so login_shell = "{{ system_brew_prefix }}/bin/zsh" works. #14572, #14570 (@jdx)

  • vfox PreInstall hooks can return a headers table next to url and sha256. Plugins can now download private or token-gated artifacts through the normal install path, which handles checksums, retries and lockfile URLs. Headers are sent only to the origin of url, are dropped on cross-origin redirects, are redacted in debug output and are never written to mise.lock. An explicit Authorization header overrides netrc and the automatic GitHub token. #14531 (@jdx)

  • mise doctor reports a stale mise-shim.exe on Windows. In windows_shim_mode = "exe", shims are copies of the mise-shim.exe that sits beside mise.exe. If that template is older than mise, or has no version tag (every template built before this release), mise doctor reports it and mise reshim warns. To fix it, update mise with the package manager that installed it, or run mise self-update, and then run mise reshim --force. #14586 (@jdx)

Fixed

  • Lockfiles
    • Running mise lock on Windows now records ruby entries for Windows, Linux and macOS platforms. Before, it skipped them, and mise install --locked then failed. #14520, #14529 (@jdx)
    • Commands that rewrite mise.lock without locking again, such as mise link, no longer delete other platforms' option variants (for example, per-platform asset_pattern entries). #14519 (@jdx)
    • A mise link for one version of a tool no longer makes mise install --locked fail for that tool's other versions. A link now bypasses the lockfile only when the requested version could select it. #14539 (@jdx)
    • mise install --locked for Java no longer fetches the mise-java catalog when mise.lock already has the download URL, so locked installs work in air-gapped or proxied environments. #14534 (@jdx)
  • Tasks and shims
    • mise run no longer hangs when parallel tasks need to install the same tool. #14536 (@jdx)
    • Running mise install inside a task no longer removes the shims for that task's lazy tools. #14533 (@jdx)
    • Task hooks (such as postinstall = { task = "setup" }) and watch_files task hooks now run with mise even when a tool shim triggered them. Before, they could fail with errors like jq: Unknown option --cd. #14550 (@jdx, @alitas)
    • mise watch exits quietly with status 130 when you interrupt watchexec with Ctrl+C, instead of printing an error. #14541 (@jdx)
  • Per-version tool options
    • When a github:, gitlab: or forgejo: tool lists several versions in config, each version now installs with its own options. Before, an option such as rename_exe set only on the first entry applied to every version. #14537 (@JamBalaya56562)
    • vfox: plugin hooks now receive only the options configured for the version they handle. #14562 (@JamBalaya56562)
  • mise install now restores cargo, rustc and the host's rust-std when they are missing from a Rust toolchain with the minimal or default profile. Before, mise reported such a toolchain as installed. #14525 (@JamBalaya56562, @risu729)
  • The uv, pip and poetry deps providers now run again after mise recreates a deleted venv in a later process. Before, the new venv stayed empty. #14532 (@halms)
  • vfox plugins now report an error, instead of crashing mise, when the HTTP client can't be built (for example, when no CA certificates are installed). #14576 (@JamBalaya56562)
  • MCP resource read errors now include the underlying cause, such as the untrusted-config message and its mise trust hint. #14566 (@diogochaves)

Registry

  • xcsift 1.7.0 and later installs from signed Packslip releases and now supports Linux x64 as well as macOS ARM64. #14540 (@jdx)
  • protoc-gen-connect-go 2.x now installs from the /v2 Go module path, and 1.x versions keep working. #14545 (@jdx)
  • Added rea (npm:rea-agents). #14421 (@phucisstupid)

Documentation

  • The docs now state that OpenTelemetry export and spinel installs require experimental = true. #14552 (@ZainnQureshii)

New Contributors

Full Changelog: v2026.10.12...v2026.10.13

💚 Sponsor mise

mise is built and maintained by @jdx, an open source developer at entire.io, the title sponsor of his open source work.

If mise saves you or your team time, please consider becoming an individual or company sponsor. Your support funds ongoing development and helps keep mise fast, free, and independent.

Don't miss a new mise release

NewReleases is sending notifications on new releases.