github jdx/mise v2026.9.18
v2026.9.18: Remote config includes, OCI task catalogs, and a trust fix for inline tool options

2 hours ago

mise.toml can now include a shared config file from a git repository or OCI registry, and task_config.includes accepts OCI artifacts. The release also closes a trust bypass that could send GITHUB_TOKEN to an attacker-controlled host, adds gem registry sources, and fixes several daemon and dotfiles problems.

Security

  • Inline tool options now require trust. Before this change, a mise.toml in an untrusted directory could hide options in a tool key, for example a github: tool key with [api_url=...] pointing at another host. mise loaded the file without trust because the value was a plain version string. Commands such as mise ls, env, current, outdated, upgrade --dry-run and latest then sent GITHUB_TOKEN to that api_url. Now any tool key that contains [ requires trust, the same as { ... } option tables already did. Plain keys like node or "cargo:eza" still load without trust. If you use inline options in a project you haven't trusted yet, run mise trust. MISE_SAFE=1 still skips trust checks entirely. #13849

Added

  • Include shared config from git or OCI. Organizations can keep tool versions, env and hooks in one place and pull them into every repo: #13843

    include = [
      "git::<repo-url>//mise.toml?ref=main",
      "oci::ghcr.io/myorg/platform-config@sha256:0f1e2d3c...",
    ]
    
    [tools]
    node = "22"   # the file's own entries override the included ones

    A git:: include points at a .toml file in a repository. An oci:: include points at an artifact with a mise.toml at its root. The included file is merged beneath the file that includes it, and a later include overrides an earlier one. It uses that file's trust, config root and lockfile. A fragment may contain [tools], [tool_alias], [env], [vars], [hooks], [alias], [shell_alias], [plugins], [wrappers] and min_version. Anything else is an error, including nested include, [settings], tasks, [dotfiles] and [daemons].

    • An untrusted config never fetches, and safe mode never fetches for project config.
    • Paranoid mode requires a full commit sha or an OCI digest.
    • Fragments are cached in MISE_CACHE_DIR/config-includes. Pinned refs are never fetched again. Branches and tags are refreshed after fetch_remote_versions_cache expires, and only by commands that check remote versions, such as install, up and use. If a refresh fails, the cached copy is used with a warning.
  • OCI task catalogs. task_config.includes accepts oci:: references, in addition to git::. The artifact is pulled, verified against its digests, cached in MISE_CACHE_DIR/remote-oci-tasks-cache, and loaded like a local task directory. Credentials come from docker login/podman login. Artifacts with symlinks or special files are rejected. Signatures are not verified, so pin @sha256: if you need the contents to stay the same. #13820

    [task_config]
    includes = ["oci::ghcr.io/myorg/shared-tasks:1.0.0"]
    oras push ghcr.io/myorg/shared-tasks:1.0.0 build.toml scripts/deploy
  • mise bootstrap --from accepts ?ref= to select a branch, tag or commit, for example mise bootstrap --from 'git::<repo-url>?ref=v1'. The git:: prefix is optional. With --update, mise resolves the ref on origin again and fast-forwards branches. A ref that was deleted upstream is an error. #13822

  • Install a gem from a specific registry. The new source option sends version lookup and install for one gem to that registry, and leaves the machine's gem sources unchanged. Credentials in the URL are redacted from logs and install metadata. #13391 (@waynehoover)

    [tools]
    "gem:internal-tool" = { version = "latest", source = "<registry-url>" }

    A GitHub Packages source (the rubygems.pkg.github.com host) without credentials now uses the GitHub token mise already resolves. The token needs read:packages. GitHub Packages has no versions API, so you must pin an exact version there. #13832 (@waynehoover)

  • mise lock --sidecars lists the native dependency sidecar directories (aube for npm, uv for Python) that must be committed along with mise.lock. It doesn't resolve, install or write anything. It marks missing sidecars, follows symlinked lockfiles, and supports --json for tools such as Renovate. #13819

  • Daemon presets export their named ports as environment variables, for example CRDB_HTTP_PORT for a cockroachdb daemon named crdb, or AUTHZ_HTTP_PORT and AUTHZ_METRICS_PORT for a spicedb daemon named authz. The values include worktree offsets from port = "auto" and any ports.* overrides, so you can use them in [env] without working out the port yourself. #13835

  • proxy_idle_timeout for daemons is now documented, typed in the JSON schema and validated. Set a duration such as "30m" to stop a proxy-started daemon, and then its dependencies, after that long without traffic. Set it to false to opt out. mise rejects true, bare numbers and values that don't look like durations, and names the daemon in the error. This requires pitchfork 2.27.0. #13830, #13836

  • Registry: added lstk, the CLI that replaces LocalStack's old one. Installing localstack now warns that it is deprecated and suggests mise use lstk. Registry entries can now set a deprecated message. #13817

Fixed

  • mise generate install-script no longer panics with or without --version. The generated wrapper now passes its pinned version to the installer. Before, a wrapper named for one release could install and keep running an older one. Without --version, the pin is the release mise self-update would pick. #13816
  • mise oci build, push and run no longer fail on a required env var when the project's [oci.env] gives it a value. You can now use a placeholder for a secret that only exists at runtime. Other commands still require the variable. #13821
  • mise lock now prints a warning with the cause when it skips a tool, for example a GitHub rate limit, instead of only counting it as skipped. You get one warning per tool. #13831
  • Daemons:
    • mise daemons start|stop|restart --all now works and applies to every daemon in the current project. Before, pitchfork rejected the command. --all can't be combined with daemon names or --group. #13827
    • The first mise daemons start or restart now installs the preset's tool. Before, it failed with a false "requires ... but [tools] selects ..." error. Only the tools of the requested daemons and their dependencies are installed. #13837
    • URLs printed for projects without an explicit [daemons_settings] namespace now route through pitchfork's proxy instead of returning 404. This needs a pitchfork that supports config add --label. mise checks for the flag itself and picks it up when pitchfork is upgraded. #13833
    • When an automatically allocated daemon port is already taken, mise explains how to pin a different port in mise.local.toml. mise no longer adds its own error lines after pitchfork's message, and it exits with pitchfork's status. #13839
  • Dotfiles:
    • mise dot and other commands that use mise's internal Git calls work again with Git for Windows 2.56. #13812 (@genskyff)
    • After an upgrade, the history watcher now notices that the mise binary was replaced, saves pending edits and exits so the service manager restarts it on the new version. A watcher started by hand with mise dot watch has to be started again. mise dot status now says when captures are failing. #13845

Full Changelog: vfox-v2026.9.19...v2026.9.18

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