Skip to content

v2026.7.12: Safe mode, node-free npm, and a built-in OCI push client

Latest

Choose a tag to compare

@mise-en-dev mise-en-dev released this 23 Jul 01:54
Immutable release. Only release title and notes can be modified.
v2026.7.12
f98d8cb

This release centers on running mise safely against untrusted config, shipping node-free npm: version resolution and installs, and replacing external tools (skopeo/crane, gpg) with built-in, dependency-free implementations. Along the way it fixes a prefer_offline timeout regression, several config/env correctness issues, and platform-specific problems on Windows and macOS.

Highlights

  • New MISE_SAFE=1 mode turns mise into an inert config reader so automation (CI, Renovate) can run mise lock --bump against untrusted branches without trust prompts or arbitrary code execution.
  • The npm: backend no longer needs node or npm installed to resolve or install packages — version metadata is fetched over HTTP and installs run in-process via the embedded aube package manager.
  • mise oci push gained a full built-in registry client: no more skopeo/crane, with blob dedup, chunked uploads, retries, cross-repo mounts, layer reuse from prior images, and multi-arch image indexes.

Added

  • Safe mode: a new global-only safe setting (MISE_SAFE=1) makes mise refuse or ignore anything that would let project config execute code or inject environment. Blocked (with errors): template exec()/read_file(), _.source, hooks, tasks, asdf plugin scripts, and plugin installs. Ignored: project [env], _.path, _.file, [shell_alias], and [settings]. HTTP-based version resolution, lockfile refresh/bump, and already-installed/embedded plugins keep working. Because a config loaded this way is inert, safe mode also skips the trust requirement. (#11146, #11151 by @jdx)

    MISE_SAFE=1 mise lock --bump --dry-run --json   # detect updates with zero code execution, no trust needed
  • mise lock --bump: advance fuzzy lockfile selectors (latest, lts, prefixes like "20") to the newest matching remote versions without installing anything and without touching mise.toml. Exact pins stay put. Pairs with --json and --dry-run for a CI job that opens lockfile-only PRs. (#11145 by @jdx)

    $ mise lock --bump --dry-run --json
    [{ "name": "node", "backend": "core:node", "old_versions": ["22.14.0"], "new_versions": ["22.15.0"] }]
  • Node-free npm: backend: mise ls-remote npm:* and latest resolution now query the npm registry directly over HTTP, and installs run in-process through the embedded aube package manager. node is only needed to run installed tools (and their lifecycle scripts), not to install them. User ~/.npmrc, scoped registries, auth, and minimum_release_age are honored. A new npm.shell_out setting (MISE_NPM_SHELL_OUT) routes both metadata and installs through the npm CLI for setups relying on npm-only config like cafile or client certs. (#11147, #11149 by @jdx)

  • Built-in OCI registry client: mise oci push no longer requires skopeo or crane. It uses an in-tree OCI Distribution client that uploads only blobs the registry is missing, resolves credentials the way docker/podman do (docker login/podman login is all the setup needed), and answers registry auth challenges so private base-image pulls via --from also work. mise oci run --engine docker now streams the image into docker load instead of needing skopeo. The --tool flag was removed. (#11132 by @jdx)

  • OCI push robustness: large layers upload in 64 MiB chunks, transient failures retry with mise's standard backoff, base layers are mounted cross-repo (?mount=) when they already live on the destination registry (zero bytes transferred), and pushes/pulls now show byte progress. A new oci.insecure_registries setting opts non-loopback registries into plain HTTP. (#11141 by @jdx)

  • OCI layer reuse: mise oci push reuses unchanged tool layers from the previously pushed image (or --cache-from REF), skipping the tar/gzip build entirely — reused tools don't even need to be installed locally. --no-cache forces a full rebuild. (#11142 by @jdx)

  • Multi-arch OCI images: mise oci push --update-index points a tag at an OCI image index and upserts the current platform while preserving entries pushed by other architectures, so one runner per arch can assemble a multi-arch tag. (#11144 by @jdx)

  • Built-in signature verification: Node.js and Swift download signatures are now verified in-process with the pure-Rust rPGP crate against the bundled keyrings, dropping the external gpg binary dependency. Note: previously, if gpg was missing and the setting was unset, verification was silently skipped; now verification always runs when enabled — opt out with gpg_verify = false. (#11148 by @jdx)

  • Relative bootstrap repo paths: [bootstrap.repos] destination keys can now be relative paths, resolved against the declaring project's root (with guards preventing escape outside the project tree), making a project's mise.toml portable across machines. (#11155 by @lilienblum)

Fixed

  • http: mise lock, ls-remote, outdated, and upgrade no longer get capped to a single 3s no-retry attempt when prefer_offline is set — they honor the configured fetch_remote_versions_timeout and retry budget again, fixing spurious timeouts. Interactive fast paths keep their bounded behavior. (#11190 by @jdx)
  • lock: unfiltered mise lock no longer prunes OS-restricted tool entries (e.g. os = ["macos"]) when run on a platform that doesn't target them, keeping shared lockfiles stable across platforms. (#11175 by @jdx)
  • env: values loaded from _.file env files now resolve references to variables defined in earlier files or [env] blocks instead of collapsing to empty, fixing flaky dotenv behavior. (#11158 by @Marukome0743)
  • env: [env] _.source now works on Windows by resolving a real POSIX bash (Git Bash / MSYS2, honoring MISE_BASH_PATH) instead of the WSL launcher or a missing bash.exe, and correctly filters MSYS runtime noise and converts prepended PATH entries back to Windows form. (#11097 by @JamBalaya56562)
  • config: trusted_config_paths (MISE_TRUSTED_CONFIG_PATHS) now overrides configs previously added to the ignore list, so a settings-trusted config is actually discovered and loaded. (#11152 by @JamBalaya56562)
  • config: env/vars array parsing is now consistent — accidental array forms for vars and task env/vars are rejected with clear errors, while the intentional [[env]] and directive-level arrays (_.source, _.file, _.path) remain supported. (#11060 by @risu729)
  • config: mise config set no longer panics when descending into a non-table value. (#11153 by @Marukome0743)
  • config: clearer warnings for unsupported semver ranges. (#11176 by @risu729)
  • hook-env: entering a directory with an untrusted config now prints a single concise warning (... is not trusted, run 'mise trust' to enable it) instead of the full error chain. Explicit commands still show the full trust error and prompt. (#11159 by @lilienblum)
  • activate: mise activate zsh no longer hangs non-interactive login shells under Rosetta — a v2026.7.11 regression where env-state snapshotting autoloaded the zsh/parameter module via dlopen. (#11188 by @jdx)
  • brew-cask: case-insensitive app bundle lookup (fixing casks like yaak) and correct resolution of preflight-generated wrapper scripts on the extract stage (fixing vlc). (#11164 by @donbeave)
  • brew: cask binaries can symlink into /usr/local on arm64. (#11174 by @jdx)
  • backend: qualified prerelease suffixes are now detected correctly. (#11179 by @risu729)
  • completions: avoid a network lookup during usage completion. (#11169 by @jdx)
  • link: clear a stale incomplete marker when linking a tool. (#11150 by @Marukome0743)
  • shim: unresolved Windows exe-shim dispatch (e.g. a project-scoped tool run outside the project) now shows the actionable "no version is set" guidance instead of an opaque "cannot find binary path". (#11189 by @jdx)
  • vfox: preserve inner quotes when a vfox Lua command dispatches through cmd.exe on Windows, fixing commands such as the Yarn 2+ install flow. (#11166 by @finalchild)
  • github/gitlab/forgejo: statically-linked linux-musl assets are now considered a fallback for Android/Termux when a package publishes no Android-specific asset, so tools like starship, bat, and hk can install there. (#10730 by @bltavares)
  • deps: avoid installing tools during dry runs, and enforce the experimental gate for task providers. (#11016, #11177 by @risu729)

Documentation

  • Document environment-variable backing for file-task arguments and flags, including CLI/env/default precedence. (#11165 by @zeitlinger)

Breaking Changes

  • mise oci push --tool has been removed. Use mise oci build -o ./img followed by skopeo copy if you need the old escape hatch. (#11132)
  • Node/Swift signature verification now always runs when enabled (external gpg is no longer required). If you relied on a missing gpg binary to skip verification, set gpg_verify = false explicitly. (#11148)
  • The unreleased npm.use_npm_view setting is replaced by npm.shell_out (MISE_NPM_SHELL_OUT). (#11149)

New Contributors

Full Changelog: v2026.7.11...v2026.7.12

💚 Sponsor mise

mise is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools. Development is funded by sponsors.

If mise saves you or your team time, please consider sponsoring at jdx.dev. Individual and company sponsorships keep mise fast, free, and independent.