Skip to content

init: fix command injection in bash Tab completion (compgen -W expansion) - #696

Merged
xdelaruelle merged 3 commits into
envmodules:mainfrom
xdelaruelle:issue-completion-injection
Sep 7, 2026
Merged

init: fix command injection in bash Tab completion (compgen -W expansion)#696
xdelaruelle merged 3 commits into
envmodules:mainfrom
xdelaruelle:issue-completion-injection

Conversation

@xdelaruelle

Copy link
Copy Markdown
Collaborator

No description provided.

…ion)

_module_comgen_words_and_files() fed untrusted text (module names read
off disk, LOADEDMODULES, MODULEPATH) straight into `compgen -W`, which
performs a full unquoted-word expansion on its wordlist -- including
command substitution -- as a normal, documented part of its behavior.
A module name, loaded-module entry, or MODULEPATH component containing
e.g. `$(...)` therefore ran arbitrary shell code the moment a user
pressed Tab.

Fix: never hand candidate text to `compgen -W`. The new
_module_comgen_words() splits the candidate list with `read -r -d ''`
(pure IFS word-splitting, no expansion of any kind) and does the
prefix match itself; _module_comgen_words_and_files() now layers the
nospace-for-directory-entries behavior on top of it. Every call site
that previously built a compgen -W wordlist from LOADEDMODULES,
MODULEPATH, or a stash/save collection name now goes through one of
these two functions instead.

Fixes CVE-2026-85013

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Xavier Delaruelle <xavier.delaruelle@cea.fr>
Adds injection-safety cases to the completion DejaGnu tool
(testsuite/completion.00-init/021-bash.exp) covering the fix in the
previous commit: a crafted module name, LOADEDMODULES entry, and
MODULEPATH entry embedding shell code must be listed as an inert
candidate string and never executed, verified by checking a marker
file the payload would touch if it ran (completion_assert_no_exec,
new in 006-procs.exp).

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Xavier Delaruelle <xavier.delaruelle@cea.fr>
…on fix

The bash fix in a previous commit only applied to bash: the unquoted-
word expansion compgen -W performs on its candidate string is specific
to that one builtin. init/zsh-functions/_module.in hands candidates to
'compadd -a <array>', init/fish_completion to 'complete -a "(...)"'
(newline-split command output), and init/tcsh_completion.in to a plain
backtick command's word list -- in all three, each element becomes a
literal candidate string with no further shell expansion, so none of
them were ever vulnerable to this bug class.

Add the same three injection-safety cases (a malicious module name,
LOADEDMODULES entry, and MODULEPATH entry, each embedding shell code)
to 031-zsh.exp/041-fish.exp/051-tcsh.exp, to guard against a future
regression rather than a known vulnerability. Each shell has its own
candidate-display conventions, which change what the literal "contains"
check needs to look for: zsh backslash-escapes special characters
before display/insertion, fish single-quotes a candidate containing a
special character on single-candidate inline completion and (on a
multi-candidate pager listing) strips a "(...)" suffix as if it were a
candidate's own description, colliding with the embedded parentheses
in the crafted candidate itself. fish has no MODULEPATH case: 'unuse'
does not list modulepaths there at all. None of this affects the
actual security check (completion_assert_no_exec, confirming that the
crafted candidate's 'touch' side effect never ran), which needs no
such per-shell handling.

Also widens the completion timeout for the new section in
051-tcsh.exp: each case there spawns a cold tcsh session with nothing
having already warmed up the pty/subprocess pipeline before listing
candidates, which occasionally ran past the default 10 second bound
under a loaded machine.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Xavier Delaruelle <xavier.delaruelle@cea.fr>
@xdelaruelle
xdelaruelle merged commit 25c32ec into envmodules:main Sep 7, 2026
20 checks passed
@xdelaruelle
xdelaruelle deleted the issue-completion-injection branch September 7, 2026 04:49
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.

1 participant