A security-focused patch release that moves the shell-completion spec cache out of world-writable /tmp into a private per-user cache dir, plus a Markdown renderer fix that stops mangling < inside fenced code blocks.
Fixed
-
Completion spec cache is no longer written to world-writable tmp (#727, fixes #722). The generated bash, zsh, fish, and nu completion scripts previously cached the usage spec at a predictable path under
${TMPDIR:-/tmp}. Because/tmpis typically world-writable and the filename is guessable, another local user could pre-plant a symlink there and have the completion script's>|/save -foverwrite an arbitrary file owned by the invoking user. Caches now live in a per-user directory created with mode700:- bash / zsh / fish:
${XDG_CACHE_HOME:-$HOME/.cache}/usage - nu:
($env.XDG_CACHE_HOME? | default (home-dir | path join ".cache") | path join "usage")
Because
~/.cachepersists across reboots (unlike/tmp), version-keyed cache files are now reaped on a cache miss if they haven't been regenerated in 30 days. The prune is age-based and scoped to the current bin, so running two versions of the same tool concurrently no longer thrashes the cache. Users who regenerate their completion scripts will pick up the fix; the cache location change is otherwise transparent. - bash / zsh / fish:
-
nu: completion cache dir permissions and nushell 0.110+ compatibility (#731). Nushell's builtin
mkdirhas no mode flag, so the initial fix in #727 created the nu cache dir at the process umask (usually755, world-readable). The generator now runs^chmod 0700on the dir at creation time (non-Windows only) to match bash/zsh/fish. Separately,$nu.home-pathwas renamed to$nu.home-dirin nushell 0.110.0, which broke the completer on any recent nushell even whenXDG_CACHE_HOMEwas set (becausedefault's argument is evaluated eagerly). The lookup now uses optional access with a fallback that works on both old and new nushell:let spec_dir = ($env.XDG_CACHE_HOME? | default ($nu.home-dir? | default $nu.home-path? | path join ".cache") | path join "usage")
-
markdown: preserve HTML inside fenced code blocks (#720) — thanks @risu729. The Markdown renderer's HTML-escape filter processed lines independently and would turn
<into<even inside multiline fenced code blocks, corrupting examples likeecho <value>. It now tracks fenced-block state across lines and leaves content between column-zero triple-backtick fences untouched, while still escaping<in surrounding prose. Addresses the escaping problem reported in jdx/mise#6949. -
cli: avoid trailing semicolon in macro expression position (#729). The two
miette::bail!("unsupported shell: ...")match arms incomplete_wordandusage_specwere wrapped in a block so the macro expands in statement position. This clears thesemicolon_in_expressions_from_macroslint that is already a hard error on nightly Rust. Runtime behavior is unchanged. -
lib: remove needless borrows in
format!args (#726) — minor cleanup for newer clippy.
Full Changelog: v3.5.5...v3.5.6
💚 Sponsor usage
usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.