Skip to content

fix: shell-quote the working directory in the distributed launch script - #4189

Merged
zcbenz merged 1 commit into
ml-explore:mainfrom
bunlongheng:fix-launch-cwd-shell-quote-sec
Aug 12, 2026
Merged

fix: shell-quote the working directory in the distributed launch script#4189
zcbenz merged 1 commit into
ml-explore:mainfrom
bunlongheng:fix-launch-cwd-shell-quote-sec

Conversation

@bunlongheng

Copy link
Copy Markdown
Contributor

What

RemoteProcess.make_launch_script in python/mlx/_distributed_utils/launch.py builds a bash script that is run on each node (locally via Popen(..., shell=True, executable="/bin/bash") and remotely over ssh). The working directory (--cwd, falling back to os.getcwd()) is interpolated into that script using Python's repr():

d = cwd or os.getcwd()
script += f"if [[ -d {repr(d)} ]]; then "
script += f"  cd {repr(d)}; "

repr() is not a shell-quoting function. When the string contains a single quote, repr() switches to a double-quoted form, and bash performs command substitution / variable expansion inside double quotes. Every other value interpolated into this same script (env values, file contents, the command itself, the host) is correctly escaped with shlex.quote; only the working directory uses repr.

Why it matters

A working directory such as:

/tmp/a'$(touch /tmp/pwned)'b

renders as cd "/tmp/a'$(touch /tmp/pwned)'b", and bash executes the $(...) substitution. This turns a value that is only supposed to name a directory into arbitrary shell execution, on every node the job is launched on. It also breaks legitimately-named directories that contain a ' or $, so it is a correctness bug as well as an injection vector when the launch command (and its --cwd) is assembled programmatically or from a job/orchestration layer.

Reproduction:

from mlx._distributed_utils.launch import RemoteProcess
print(RemoteProcess.make_launch_script(0, None, "/tmp/a'$(touch /tmp/pwned)'b", {}, [], ["true"], True))
# -> ... cd "/tmp/a'$(touch /tmp/pwned)'b"; ...   (the $(...) runs under /bin/bash)

Fix

Quote the directory with shlex.quote (already imported and already used for every other interpolation in this function) instead of repr. Also corrects the adjacent >2 typo to >&2 so the error message goes to stderr. No API change.

d = cwd or os.getcwd()
qd = shlex.quote(d)
script += f"if [[ -d {qd} ]]; then "
script += f"  cd {qd}; "
...
    script += f" echo 'Failed to change directory to' {qd} >&2; "

Test

import shlex, subprocess
d = "/tmp/a'$(touch /tmp/pwned)'b"
script = f"if [[ -d {shlex.quote(d)} ]]; then cd {shlex.quote(d)}; fi"
subprocess.run(script, shell=True, executable="/bin/bash")
# /tmp/pwned is NOT created; the value is treated as a literal path

Before the change the same test with repr(d) creates /tmp/pwned.

@zcbenz
zcbenz merged commit d34f630 into ml-explore:main Aug 12, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants