fix: strip shims from PATH in credential and template subprocesses#8802
fix: strip shims from PATH in credential and template subprocesses#8802
Conversation
Greptile SummaryThis PR fixes a fork-bomb vulnerability where subprocess-spawning code paths in mise inherited the shims directory in PATH, causing mise-managed tools (e.g.
Confidence Score: 4/5The runtime fix is correct and safe to merge; the credential e2e test needs a revision to actually guard against regression. The three production-code changes are sound and follow established patterns in the codebase. However,
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant mise
participant tera_exec
participant github_rs as github.rs
participant subprocess
User->>mise: cd into project / hook-env
mise->>tera_exec: evaluate exec() template
tera_exec->>tera_exec: clone PRISTINE_ENV, strip shims via strip_shims_from_path()
tera_exec->>subprocess: spawn shell (PATH without shims)
subprocess-->>tera_exec: real binary output
User->>mise: GitHub API call (ls-remote, install)
mise->>github_rs: resolve_token()
github_rs->>github_rs: path_env_without_shims()
github_rs->>subprocess: sh -c credential_command (PATH without shims)
subprocess-->>github_rs: token
github_rs->>subprocess: git credential fill (PATH without shims)
subprocess-->>github_rs: password= token
Reviews (8): Last reviewed commit: "[autofix.ci] apply automated fixes" | Re-trigger Greptile |
There was a problem hiding this comment.
Code Review
This pull request prevents infinite recursion during credential resolution by stripping mise shims from the PATH environment variable in both get_credential_command_token and get_git_credential_token. A review comment suggests extracting the duplicated path-filtering logic into a shared helper function to improve maintainability and reduce code duplication.
bb1d42b to
186f002
Compare
|
@jdx — This is the same class of shim-recursion fork bomb fixed in PRs #8475, #8276, #8560, #8402, and #8189, but in the two remaining subprocess-spawning paths in |
186f002 to
aa48e25
Compare
|
Updated — found a third recursion vector that was the primary trigger all along:
This is independent of the @jdx would appreciate a review when you get a chance — this affects anyone who uses |
|
Linking related discussion: #6374 — same user-facing symptom ("Cannot fork") caused by the tera Also note: |
927154e to
5fc984e
Compare
get_credential_command_token() and get_git_credential_token() spawn subprocesses (sh -c <cmd> and git credential fill) that inherit the current PATH, including mise shims. When the credential tool (e.g. gh) or git is managed by mise, the shim calls mise exec, which may re-enter token resolution, spawning the same command indefinitely. This causes a recursive fork bomb that can produce thousands of processes and make the system unresponsive (observed load average >1800 on an ARM SBC running k3s). Apply the same shim-stripping pattern used in dependency_env() (PR jdx#8475) and exec_program() (PR jdx#8276): filter dirs::SHIMS out of PATH before spawning the subprocess.
5fc984e to
0f0f4b6
Compare
### 🚀 Features - **(python)** add GitHub provenance verification for prebuilt binaries by @malept in [#8820](#8820) ### 🐛 Bug Fixes - **(ci)** use rustls-native-roots for Windows CI build by @jdx in [#8822](#8822) - **(go)** improve version fetching logic to support deeply nested sub-modules by @roele in [#8823](#8823) - **(shim)** prevent infinite recursion when system shims dir is on PATH by @andrewthauer in [#8816](#8816) - go backend missing supports_lockfile_url() override by @palootcenas-outreach in [#8790](#8790) - strip shims from PATH in credential and template subprocesses by @antonioacg in [#8802](#8802) ### 📚 Documentation - fix typo in shims documentation for fish by @roele in [#8798](#8798) ### 📦️ Dependency Updates - update ghcr.io/jdx/mise:alpine docker digest to 3e6d001 by @renovate[bot] in [#8794](#8794) - pin dependencies by @renovate[bot] in [#8793](#8793) ### 📦 Registry - fix flutter version sorting by @roele in [#8818](#8818) - add svgo (npm:svgo) by @3w36zj6 in [#8817](#8817) ### New Contributors - @antonioacg made their first contribution in [#8802](#8802) - @palootcenas-outreach made their first contribution in [#8790](#8790) ## 📦 Aqua Registry Updates #### New Packages (3) - [`RasKrebs/sonar`](https://github.com/RasKrebs/sonar) - [`emacs-eask/cli`](https://github.com/emacs-eask/cli) - [`superradcompany/microsandbox`](https://github.com/superradcompany/microsandbox) #### Updated Packages (4) - [`dimo414/bkt`](https://github.com/dimo414/bkt) - [`lxc/incus`](https://github.com/lxc/incus) - [`shinagawa-web/gomarklint`](https://github.com/shinagawa-web/gomarklint) - [`updatecli/updatecli`](https://github.com/updatecli/updatecli)
Summary
Three code paths spawn subprocesses that can invoke mise-managed tools (e.g.
gh,git) without stripping mise shims from PATH. When the tool resolves to a mise shim, it re-enters mise, which may trigger the same subprocess again — causing infinite recursion (fork bomb).Observed: load average >1800 on an ARM SBC, system unresponsive. Also reproduced on macOS.
Root Cause
Three subprocess-spawning paths inherit shims in PATH:
1.
credential_commandinsrc/github.rsget_credential_command_token()runssh -c <cmd>(e.g.gh auth token). Ifghis a mise shim → recursion.2.
git credential fillinsrc/github.rsget_git_credential_token()runsgit credential fill. Ifgitis a mise shim, or git's credential helper invokesgh(viagh auth setup-git) → recursion.3.
exec()template function insrc/tera.rs(primary trigger)When a
.mise.tomlcontains:Every
mise hook-envin that directory runsgh auth tokenviatera_exec()withPRISTINE_ENV, which includes shims in PATH →ghshim →mise exec→ evaluates env → runsgh auth tokenagain → infinite recursion.This is the most common trigger because
exec()in[env]is the idiomatic way to derive env vars from CLI tools.Fix
Add a shared
file::path_env_without_shims()helper (next to the existingwhich_no_shims()) that filtersdirs::SHIMSout of PATH and returns anOsStringsuitable for.env("PATH", ...). Used in all three call sites:src/github.rs:get_credential_command_token()andget_git_credential_token()src/tera.rs:tera_exec()Follows the same shim-stripping pattern established in:
dependency_env())exec_program())uvvenv creation viawhich_no_shims())Related: Discussion #6374 — same user-facing symptom ("Cannot fork") from
exec()path.Reproduction
Tera exec path (most common)
ghvia mise (gh = "latest").mise.tomlwith[env] GITHUB_TOKEN = "{{exec(command='gh auth token')}}"cdinto that directory —mise hook-envfires, evaluates the template, runsgh auth tokenthrough the shim → fork bombCredential command path
ghvia mise, setcredential_command = "gh auth token"in mise settingsChanges
src/file.rs: Newpath_env_without_shims()public helper — shared by all call sitessrc/github.rs: Use shared helper inget_credential_command_token()andget_git_credential_token()src/tera.rs: Use shared helper intera_exec()e2e/cli/test_github_credential_shim_recursion: e2e test for credential_command pathe2e/cli/test_tera_exec_shim_recursion: e2e test for tera exec() pathNote on env var workaround
Setting
MISE_GITHUB_TOKEN=""does not prevent the hang —resolve_token()filters empty strings with.filter(|t| !t.is_empty()), so it falls through to subprocess-based fallbacks. A non-empty sentinel value (e.g.MISE_GITHUB_TOKEN="none") works for the github.rs paths but the teraexec()path is independent of token resolution entirely.Test plan
cargo checkpassescargo testpassestest_github_credential_shim_recursionpassestest_tera_exec_shim_recursionpassesexec(command='gh auth token')in.mise.toml,cddoes not fork-bomb