1. Executive summary
An incomplete fix in the mise developer toolchain leaves four shell-interpreter settings out of the global_only denylist that the CVE-2026-55448 remediation relies on, so an untrusted .mise.toml in a cloned repository can set the interpreter used for every command mise spawns and achieve arbitrary command execution without any trust prompt. The flaw is source-verified at HEAD 7160170206782fdd3ef287c8302369e32152fb71 but has not been run end to end, and no CVE identifier has been assigned to it in the material reviewed. The three related CVEs carry only moderate-to-high scores and none is in CISA KEV: CVE-2026-55448 is CVSS 6.3 MEDIUM (CWE-78), CVE-2026-35533 is CVSS 7.7 HIGH (CWE-284), and CVE-2026-54557 is CVSS 5.5 MEDIUM (CWE-22), all at EPSS 0%. The exposure for EMEA financial services is not the CVSS number but the delivery path: a developer cloning an untrusted repository and running a task, install, hook or template render executes attacker-chosen code on a workstation that typically holds source, CI credentials and production access.
2. Regulatory framing
| Article | Trigger (the fact in this item) | Practical impact |
|---|---|---|
| DORA Art. 28: ICT third-party risk — general principles | mise is a third-party development toolchain component whose incomplete fix leaves a code-execution path open in the version clients run |
Clients must treat the toolchain as an in-scope ICT third-party dependency and confirm the vendor fix state before relying on it |
| NIS2 Art. 21(2)(d): supply chain security measures | The attack vector is a malicious configuration file delivered inside a cloned third-party repository | Clients need a control that governs what untrusted repository content can execute on developer endpoints |
No other article in the regulatory reference is engaged by the facts here. The item is a vulnerability disclosure with no confirmed incident, so the DORA incident-management and reporting articles (17, 18, 19) and the NIS2 reporting article (23) are not triggered unless a client confirms exploitation.
3. Technical analysis & attack chain
The defect is a gap in a denylist, not a new class of flaw. CVE-2026-55448 and CVE-2026-35533 fixed the fact that a local project [settings] table is harvested by the settings preloader independent of the trust store, meaning an untrusted .mise.toml sets settings without the user ever trusting the file. The remediation was a per-field global_only denylist: settings marked global_only are stripped from non-global config. The maintainers marked the three forge credential_command sinks (forgejo.credential_command around line 775 of settings.toml, github.credential_command around 828, gitlab.credential_command around 990) but did not mark the four shell-interpreter-args settings, which are also command-execution settings because they choose the interpreter for every command mise spawns:
unix_default_file_shell_args(settings.tomlaround 2920)unix_default_inline_shell_args(around 2926)windows_default_file_shell_args(around 3004)windows_default_inline_shell_args(around 3010)
Confirmed attack chain:
- An attacker places a
.mise.tomlcontaining a[settings]table in a repository, or in any ancestor directory of the working directory. The file is never trusted by the victim. - The settings preloader loads every config path including the local project file (
all_settings_files,src/config/settings.rsline 778). In default (non-safe) mode there is no trust check;safe_modedefaults false (src/config/settings.rsline 1141). strip_local_only_settings(src/config/settings.rsline 409) filters bymeta.global_only(line 416:filter_map(|(key, meta)| meta.global_only.then_some(*key))), so any field not markedglobal_onlysurvives from the untrusted local config. The four shell-args settings are not marked, so they survive.default_inline_shell(src/config/settings.rsline 1032) readsself.unix_default_inline_shell_args(line 1040), anddefault_file_shellreadsunix_default_file_shell_args.Settings::getreturns the merged global-plus-local value minusglobal_only, so the untrusted project value overrides the built-in default ofsh -c -o errexit.- The real command is appended after the attacker's arguments, so the payload runs and the real command is demoted to
$0. An attacker settingunix_default_inline_shell_args = "sh -c 'PAYLOAD'"producessh -c 'PAYLOAD' <command>.
The injection semantics are consistent across four invocation sites:
- tera inline
execbuiltin:src/tera.rs(tera1_execaround 1358 and around 1470) buildsshell[1..] + [command]withprogram = shell[0]. - postinstall runner:
src/backend/mod.rsaround 2405 callscmd_body_args(shell_args, body);src/cmd.rscmd_body_args(non-Windows, around 520) returnsprogram flags... body, the same demotion. - task execution:
src/task/task_executor.rs(around 916, 939, 993) usestask.shell()?.unwrap_or(default_inline_shell()/default_file_shell()), so a trusted task with no explicit shell (the common case) runs through the attacker's interpreter. - hooks:
src/hooks.rs(around 540, 603) also fall back todefault_inline_shell().
Reachability. The executed command can come from a trusted or global source; only the interpreter is attacker-controlled. Any of the following, run while the untrusted .mise.toml sits in an ancestor directory, fires the payload: mise run <task> for a task defined in the global config or a trusted parent repo (inline run, no explicit shell); mise install of any tool with a postinstall directive; any tera template that calls exec(...) in the victim's own trusted or global config; a directory-enter hook from any trusted config in scope.
Proof of concept. In an untrusted repository, .mise.toml:
[settings]
unix_default_inline_shell_args = "sh -c 'id > /tmp/mise_pwned'"
The victim cds in without trusting the file and later runs any global or trusted-parent task with no explicit shell, or mise install of a tool with a postinstall, or a config that renders {{ exec(...) }}. mise builds sh -c 'id > /tmp/mise_pwned' <realcommand>, so the payload runs.
Confidence caveats. The researcher states the flaw is source-verified at HEAD but that mise was not run end to end, so the end-to-end execution is inferred from the code paths rather than observed. The advisory is single-sourced to the GitHub advisory GHSA-g74g-rg72-j2p3; verify before enforcement. The load path itself is the same one two shipped CVEs (CVE-2026-55448, CVE-2026-35533) already proved reachable, which raises confidence in the mechanism but does not substitute for a live test.
Secondary hardening note (weaker, not the primary finding). The CVE-2026-54557 path-sanitization fix added sanitize_install_version_name only inside the HTTP backend (src/backend/http.rs around 628), while the general path builder ToolVersion::tv_pathname (src/toolset/tool_version.rs around 292) still only replaces : and / and does not neutralize .. or backslash. Impact is narrow (one level up, stays in the mise data dir on Unix), so this is a hardening note rather than a primary finding.
Discrepancy note. The verified reference data records CVE-2026-55448 as CWE-78 (OS Command Injection) and CVE-2026-35533 as CWE-284 (Improper Access Control). The source describes the same two CVEs as trust-store bypasses; both classifications describe the same flaw, and the verified values are used here.
4. Mitigation & containment
P1 (within 24h)
- Identify every developer endpoint and CI runner with
miseinstalled. Runmise --versionand record the version against the vendor fix state. No patched version is named in the source material, so treat the fix as unconfirmed until the maintainers publish one; do not assume a version is safe because it postdates the CVE-2026-55448 fix. - Where
misecannot be immediately updated or the fix state is unknown, block execution of untrusted project config by runningmisein safe mode (safe_mode = true) so the preloader applies a trust check. This is the control the source identifies as absent in default mode. - Search developer workstations and repositories for
.mise.tomlfiles containingunix_default_inline_shell_args,unix_default_file_shell_args,windows_default_inline_shell_argsorwindows_default_file_shell_argsin a[settings]table. Any such file in a repository the organisation did not author is a suspected payload.
P2 (within 72h)
- Add a pre-clone or post-clone scan that flags
.mise.toml[settings]keys outside an approved allowlist, and fail the checkout or the CI job on a hit. - Restrict
miseexecution on developer endpoints to repositories on an internal allowlist until a vendor fix is confirmed. The attack requires the victim tocdinto an untrusted repository and then run a task, install, hook or template render, so removing untrusted repositories from the working set removes the trigger. - Review CI pipelines that run
mise installormise runagainst third-party repositories. Apostinstalldirective in a tool definition is a direct execution path.
P3 (within 7 days)
- Apply the vendor fix when published. The source's suggested fix is to mark all four
*_default_*_shell_argssettingsglobal_only = true, matching the treatment ofcredential_command, or to flip default-mode policy to an allowlist so any setting not explicitly known-safe is stripped from non-global config. Until the maintainers ship one of these, the denylist gap remains. - For the secondary path-traversal hardening note, track the
ToolVersion::tv_pathnamechange separately; it is not the primary finding and does not change the P1/P2 actions.
5. Indicators of compromise
No atomic indicators (hashes, domains, IPs, file paths of dropped payloads) are present in the source material. The observable artefacts are configuration strings and file locations, which are behavioural.
| type | value | confidence | source |
|---|---|---|---|
| config key | unix_default_inline_shell_args |
high | GHSA-g74g-rg72-j2p3 |
| config key | unix_default_file_shell_args |
high | GHSA-g74g-rg72-j2p3 |
| config key | windows_default_inline_shell_args |
high | GHSA-g74g-rg72-j2p3 |
| config key | windows_default_file_shell_args |
high | GHSA-g74g-rg72-j2p3 |
| file | .mise.toml |
high | GHSA-g74g-rg72-j2p3 |
| file path | /tmp/mise_pwned (PoC output path) |
medium | GHSA-g74g-rg72-j2p3 |
Behavioural indicators
| behaviour | where to observe | confidence |
|---|---|---|
mise spawns a shell whose arguments include an attacker-supplied sh -c '...' prefix before the real command |
process creation telemetry on developer endpoints and CI runners (parent mise, child sh) |
medium |
.mise.toml in a repository or ancestor directory contains a [settings] table with any of the four shell-args keys |
file integrity monitoring, repository scanning, pre-commit hooks | high |
mise install of a tool with a postinstall directive executes a command through a non-default interpreter |
CI job logs, EDR process tree | medium |
config_key unix_default_inline_shell_args
config_key unix_default_file_shell_args
config_key windows_default_inline_shell_args
config_key windows_default_file_shell_args
file .mise.toml
file_path /tmp/mise_pwned
6. Detection
The source provides distinctive configuration strings and a PoC output path. The YARA rule targets .mise.toml files that set any of the four shell-args keys, which is the artefact of the attack itself. The Sigma rule targets the process behaviour: a mise process spawning a shell with an inline -c argument that precedes the real command.
rule MISE_Untrusted_Shell_Args_Override
{
meta:
author = "Adverse Trace"
date = "2026-10-16"
reference = "https://github.com/advisories/GHSA-g74g-rg72-j2p3"
description = "Detects .mise.toml files that set shell interpreter args in a [settings] table, the configuration override used to achieve command execution from an untrusted repository"
strings:
$s1 = "unix_default_inline_shell_args"
$s2 = "unix_default_file_shell_args"
$s3 = "windows_default_inline_shell_args"
$s4 = "windows_default_file_shell_args"
$settings = "[settings]"
condition:
$settings and any of ($s*)
}
title: mise spawns shell with attacker-controlled inline arguments
id: 8f3c1a2e-6b4d-4e9a-9c1f-2d7e5a0b3c44
status: experimental
description: Detects a mise process spawning a shell with an inline -c argument, consistent with the untrusted .mise.toml shell-args override
author: Adverse Trace
date: 2026-10-16
references:
- https://github.com/advisories/GHSA-g74g-rg72-j2p3
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentImage|endswith: '/mise'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
CommandLine|contains: ' -c '
condition: selection_parent and selection_child
falsepositives:
- Legitimate mise tasks that explicitly set a shell with -c
level: medium
CVE assessment
3 referenced CVEs
| CVE | CVSS | Exploited | EPSS | Summary |
|---|---|---|---|---|
| CVE-2026-35533 | 7.7 High | — | 0% | mise manages dev tools like node, python, cmake, and terraform. From 2026.2.18 through 2026.4.5, mise loads trust-control setti… |
| CVE-2026-55448 | 6.3 Medium | — | 0% | mise manages dev tools like node, python, cmake, and terraform. From 2026.3.15 until 2026.6.4, mise loads github.credential_com… |
| CVE-2026-54557 | 5.5 Medium | — | 0% | mise manages dev tools like node, python, cmake, and terraform. Prior to 2026.6.1, the mise HTTP backend builds its install sym… |
7. Sources
- GitHub Security Advisories, "mise permits untrusted local configuration to override default shell arguments", https://github.com/advisories/GHSA-g74g-rg72-j2p3, published 2026-10-15
- GitHub Security Advisories, "Local settings bypass config trust checks", https://github.com/advisories/GHSA-436v-8fw5-4mj8, no date given in the fetched content
- GitHub Advisory Database, "CVE-2026-103929", https://github.com/advisories/GHSA-g74g-rg72-j2p3, no date given in the fetched content
8. Adverse Trace position
Adverse Trace assesses this as a medium-severity code-execution flaw in a developer toolchain, not a critical one: the verified CVSS values for the related CVEs are 6.3, 7.7 and 5.5, none is in CISA KEV, and all sit at EPSS 0%, so there is no evidence of exploitation in the wild. The risk to EMEA financial services clients is concentrated in developer endpoints and CI runners that clone third-party repositories, where the payload executes with the developer's own privileges and typically reaches source, CI credentials and production access. The finding is single-sourced to GHSA-g74g-rg72-j2p3 and source-verified but not run end to end, so we treat the end-to-end execution as inferred rather than observed; verify before enforcing blocks. We will track the vendor fix for the four *_default_*_shell_args settings and re-issue this advisory when a patched version is named. Clients should complete the P1 identification and safe-mode step within 24 hours and report back the mise version inventory so we can correlate against the fix when it lands.
Published via PulseTrace — Adverse Trace threat intelligence.