mise-en-place

jdx/mise last check 662 releases today
Notes

The front-end to your dev env Pronounced "MEEZ ahn plahs"

Release notes
view on github
2026.10.19 · v2026.10.19: Security hardening across trust, installs and provenance; lockfiles now rebuilt completely by default · today

Most of this release closes ways an untrusted repository, download host or mirror could run code, leak credentials or get around verification. Some of these fixes make mise stricter, so check Breaking Changes before you upgrade. Also in this release: lockfile_mode = "generate" is now the default, mise lsp sends semantic highlighting, and there is a new {{ mise_config_dir }} template variable.

Highlights

  • Trust is narrower and tied to the files you trusted. Help output, shims, hooks, config writes and shell completion no longer trust a project or run its code without your consent. Trust also follows worktrees, symlinks and config directories correctly, and safe mode closes several more gaps.
  • Verification fails closed. Pinned checksums, Node signatures, SLSA provenance (including the tag it was built from) and GitHub attestations are now enforced. Before, a 404 or a missing file could make mise skip them.
  • Hostile inputs are contained. Archives, asset names, versions, lockfiles and HTTP responses can no longer write outside their directories, use unbounded memory or disk, or hang the prompt. Credentials no longer show up in install paths, lockfiles, logs or redirects.

Added

  • {{ mise_config_dir }} template variable. It resolves to the config directory mise itself uses: MISE_CONFIG_DIR, or else xdg_config_home + /mise. It is available wherever xdg_config_home is: config templates, .miserc.toml and settings paths. This is useful for dotfiles variants that link into conf.d. #14886 (@jdx, @ponko2)

    [dotfiles."git-tools"]
    source = "git"
    mode = "symlink"
    variants = [{ default = true, target = "{{ mise_config_dir }}/conf.d/git-tools" }]
    
  • Semantic highlighting in mise lsp. Editors can now color task names, tools, env vars, [vars] keys, _. directives, {{ }}/{% %}/{# #} template delimiters and deprecated keys in mise.toml. To turn it off, pass {"semanticTokens": false} in initializationOptions. #14918 (@jdx)

  • extract_max_ratio setting (global only). It caps how far an archive may expand during extraction. See Security below. #14915 (@jdx)

  • github.enterprise_hosts setting (global only, MISE_GITHUB_ENTERPRISE_HOSTS). It lists the GitHub Enterprise hosts that receive the GitHub token on /api/v3 URLs over https. #14913 (@jdx)

  • New vfox attestation fields slsa_source_repository and slsa_source_tag. Plugins can use them to pin the repository and tag that SLSA provenance must come from. #14904, #14924 (@jdx)

Changed

  • lockfile_mode = "generate" is now the default. Installs now rebuild mise.lock from the current requests, reuse unchanged entries and also lock the other platforms. A lockfile committed from one machine therefore no longer fails mise install --locked on another platform because of missing entries. Neither mode creates a lockfile (use mise lock or lockfile = true), and the lockfile format is unchanged. To keep the previous behavior, set lockfile_mode = "merge" or MISE_LOCKFILE_MODE=merge. #14893 (@jdx)

Security

Trust and safe mode

  • Several actions no longer count as consent to trust a project: printing mise run --help/mise watch --help, running a shim, a hook starting mise run, an MCP call, or mise set/unset/tasks add saving config. Config writes now ask before they trust an untrusted sibling config. A task counts as trusted only if every config that adds to it is trusted. The MCP server refuses untrusted file tasks, task names that look like file paths, and inline tool options. #14903 (@jdx)

  • Trust now stays with the files you trusted. A forged git worktree, a symlink to your global config, a clone named .mise, or a project .miserc.toml can no longer borrow trust or hide global config. In paranoid mode, idiomatic version files, each local task file and project-named aqua registries need trust of their own. Remote git includes pinned to a commit SHA must check out exactly that commit. #14902 (@jdx)

  • Safe mode (MISE_SAFE=1) now also blocks:

    • a project's lazy tools, [deps], path: versions and spm install_command;
    • all S3 requests;
    • forge tokens and netrc credentials sent to hosts that project config names;
    • env and filesystem helpers in project templates.

    In every mode, a project .miserc.toml gets a restricted, size-limited template language, and bin_path must stay inside the tool's install directory. #14900 (@jdx)

  • Pressing TAB no longer runs untrusted task code. The dynamic completers (complete run=, complete delegate=, choices run=, mount) only run for trusted config. mise's own completers quote typed words, and control characters are removed from candidates. Quoting for fish and PowerShell is also fixed. #14898 (@jdx)

  • Hook commands are now rendered once, when they load. Before, a directory name containing {{ exec(...) }} could run code from a cd hook. A project's enter, leave and watch_files hooks now start in the project root. mise use, mise upgrade --bump and every other writer refuse to write a version containing template syntax, and a rewritten option keeps its {{ env.X }} template instead of the rendered secret. #14897 (@jdx)

  • cd-ing into a hostile repository can no longer hang or crash hook-env or make mise print files from outside the repo. Causes this covers include configs linked to devices, symlink mazes in task directories, non-UTF-8 paths, oversized files, glob characters in paths, and version files that link to another file. #14916 (@jdx)

Install verification

  • A checksum pinned in mise.lock is now enforced for erlang, npm, spm and http instead of being replaced or skipped. If Node's SHASUMS256.txt.sig is missing, the install fails. bun and deno check the publisher's sha256 when there is no lock entry. A locked node or spm artifact that returns 404 no longer silently falls back to a source build. #14899 (@jdx)

  • SLSA, attestation and signed-checksum checks now fail closed:

    • the provenance file can no longer stand in for the artifact;
    • slsa_signer_* pins require provenance;
    • mise lock runs the cosign, minisign and SLSA checks that aqua recipes declare;
    • SHA-512 signed checksum files are compared with the artifact;
    • aqua honors attestations_since.

    #14908 (@jdx)

  • The SLSA signing run must come from the workflow's repository or the tool's own repository. Attestations must name the requested repository. Public-good bundles without a Rekor entry are rejected. #14904 (@jdx)

  • SLSA provenance built from a different tag is now rejected, so a mirror can't serve an older release's genuine artifact and provenance as a newer version. #14924 (@jdx)

  • packslip signer pins are checked by repository ID, including workflow pins. Backdated GitLab released_at dates and bundles with no transparency-log time can no longer get around minimum_release_age. #14912 (@jdx)

Paths, subprocesses and resource limits

  • Release asset names must be plain file names. Archives from the github, http, aqua, cargo-binstall, packslip and vfox backends may not contain symlinks that point outside the install directory. #14895 (@jdx)

  • Resolved versions, plugin names and task stub names are checked before they become paths or URL segments. A remote version containing .., quotes, $ or a leading - now fails as an invalid tool version. #14901 (@jdx)

  • Git lookups, build tools (ruby-build, python-build, cargo install, gem install) and npm now run outside the project directory, so the repo's .git/config and other project files can't change what they do. Untrusted values are kept out of their command-line arguments. In safe mode, asdf exec-env is refused. #14896 (@jdx)

  • Committed symlinks around lockfiles, tool stubs and the remote task cache can no longer make mise read, write or delete files outside the repo. An untrusted lockfile still pins versions and checksums, but it can no longer switch a tool's backend, add inline options or supply download URLs. #14906 (@jdx)

  • The task sandbox has fewer escapes:

    • --allow-write refuses project symlinks that lead outside the project;
    • --deny-net also blocks other socket families, io_uring and x32 syscalls;
    • an empty allow_write blocks all writes instead of turning the sandbox off;
    • macOS always uses /usr/bin/sandbox-exec;
    • OCI whiteouts can't delete through planted symlinks.

    #14911 (@jdx)

  • HTTP response bodies are capped at 128 MiB, and slow bodies are bounded by http_download_timeout. Downloads are saved exactly as sent. Archive extraction stops once the output exceeds both 256 MiB and 100 times the download size (extract_max_ratio). #14915 (@jdx)

Credentials

  • The GitHub token is sent only to GitHub API hosts or the configured api_url, not to any host that serves /api/v3. Release caches are keyed by the exact repository. A download that fails its pinned checksum is not kept. A project can no longer mark a task global. In safe mode, remote task files from project config are not fetched. #14913 (@jdx)
  • Credentials are now kept out of install directory names, install manifests, mise.lock, Referer headers, logs and error messages. Age keys and Forgejo tokens are redacted in mise doctor, mise settings and mise tool. Shebang task scripts are readable only by their owner, and multi-line secrets are redacted in task output. #14917 (@jdx)

Fixed

  • uv_venv_auto could fork-bomb the machine when uv probed mise's python shims while creating a venv. mise now skips venv creation when it is started from inside that venv creation. #14927 (@jdx)
  • With minimum_release_age set, mise upgrade no longer downgrades tools that use date versions with leading zeros (for example 2026.10.21 to 2026.08.19). #14923 (@jdx)
  • File tasks that extends a task template now use the template's usage spec, so its flags show in -h and are accepted. #14888 (@jdx)
  • mise tasks add --file now quotes and escapes #MISE header values. Before, --dir and values containing quotes produced invalid TOML that broke the next mise run. #14925 (@xucian)
  • mise uninstall can now remove installs whose directories deny their owner write access, such as read-only 0555 runtime trees. #14883 (@HengYangDS)
  • A pypi: tool with a private git+ssh:// github.com source now lists versions through git ls-remote over SSH when GitHub can't see the repository. #14905 (@jdx, @owpac)

Breaking Changes

Most setups need no changes. Check these cases:

  • Lockfiles: installs now rewrite mise.lock in generate mode. To keep the old behavior, set lockfile_mode = "merge".
  • Trust prompts: mise set/unset/tasks add in a directory with an untrusted sibling config now ask for trust, or fail without a terminal. A project that has only a mise-tasks/ directory needs mise trust . before its dynamic task completions work. In paranoid mode, run mise trust <file> once for each existing task file.
  • Worktrees and includes: a worktree you moved by hand needs git worktree repair before it shares trust again. A remote include pinned to an annotated tag's object ID must pin the commit SHA instead. Your own ~/.miserc.toml can no longer ignore the global config.
  • Project .miserc.toml: templates that read env or use loops or functions other than arch(), os(), os_family(), libc(), avx2() and num_cpus() are no longer rendered. Move them to the global .miserc.toml.
  • Safe mode: project templates that read an env var without a default now fail to render. Projects that point at a private forge or a netrc-protected server can no longer list versions there.
  • Node: mirrors that don't copy the .sig files, and early releases without one (for example 4.0.0 and 5.12.0), need node.gpg_verify = false.
  • SLSA: a github: tool that sets slsa_signer_identity but builds from a branch instead of a tag no longer verifies. A lock entry that has a checksum but no provenance installs on the checksum alone; re-run mise lock or set locked_verify_provenance.
  • packslip: after a repository rename, a pin without a repository ID needs mise packslip forget <tool>.
  • GitHub Enterprise: http: tools, aqua packages and remote tasks on /api/v3 URLs no longer get the GitHub token automatically. Add the host to github.enterprise_hosts in global config, or set api_url.
  • Credentials in URLs: mise lock refuses URLs whose query has a credential-like parameter. Use headers or netrc instead. Tools installed under a directory name that contained credentials are reinstalled under a clean name.
  • Task sandbox: --deny-write/allow_write sandboxes no longer start on Linux before 6.2. Programs that need io_uring no longer run under --deny-net. To allow writes through a project symlink that points outside the project, name its target instead.
  • Archives: archives that contain symlinks pointing outside the install directory fail to install (brew casks and aqua dmg/pkg are exempt). Archives that legitimately expand more than 100 times and past 256 MiB need a higher extract_max_ratio, or 0 to turn the check off.
  • Hooks: a project's enter, leave and watch_files hooks now start in the project root. Use $MISE_PROJECT_ROOT if a hook needs the root explicitly.
  • Other changes:
    • MISE_OVERRIDE_*_FILENAMES entries are matched as literal file names;
    • config, lock and task files over 16 MiB are refused;
    • a .tool-versions or idiomatic version file that links to a file with a different name is skipped;
    • a relative go.repo resolves from $HOME;
    • a bare OWNER/REPO passed to bootstrap --adopt that matches a local path is an error (write ./OWNER/REPO for the local path).

New Contributors

  • @xucian made their first contribution in #14925
  • @HengYangDS made their first contribution in #14883

Full Changelog: https://github.com/jdx/mise/compare/v2026.10.18...v2026.10.19

💚 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.