fix(completion): prevent script execution during tab completion

Fixes #13366 - Tab completion after 'git' triggers bin/test execution
Fixes #13310 - Duplicate completion candidates

The 'l:|=* r:|=*' matcher pattern in completion.zsh was causing:
1. Unintended script execution during tab completion
2. Duplicate completion candidates
3. Overly permissive matching

This pattern allowed left-side anchor matching which could cause zsh
to execute scripts like bin/test when searching for completions.

Removed 'l:|=* r:|=*' from all three configuration branches while
preserving essential functionality:
- Case-insensitive matching: m:{[:lower:][:upper:]}={[:upper:][:lower:]}
- Right-side fuzzy matching: r:|=*
- Hyphen-insensitive matching: m:{[:lower:][:upper:]-_}={[:upper:][:lower:]_-}

Testing shows that completion continues to work correctly without
the security and performance issues.
This commit is contained in:
Paul Frederiksen 2025-10-24 09:47:17 -07:00
commit 0725ed84e6

View file

@ -14,13 +14,19 @@ bindkey -M menuselect '^o' accept-and-infer-next-history
zstyle ':completion:*:*:*:*:*' menu select
# case insensitive (all), partial-word and substring completion
# NOTE: 'l:|=* r:|=*' matcher removed due to causing unexpected behavior:
# - Can trigger unintended execution of scripts during tab completion (issue #13366)
# - Causes duplicate completion candidates (issue #13310)
# - Creates overly permissive matching that degrades user experience
# The remaining matchers (case-insensitive + right-side anchor) provide all essential
# completion functionality without the problematic side effects.
if [[ "$CASE_SENSITIVE" = true ]]; then
zstyle ':completion:*' matcher-list 'r:|=*' 'l:|=* r:|=*'
zstyle ':completion:*' matcher-list 'r:|=*'
else
if [[ "$HYPHEN_INSENSITIVE" = true ]]; then
zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]-_}={[:upper:][:lower:]_-}' 'r:|=*' 'l:|=* r:|=*'
zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]-_}={[:upper:][:lower:]_-}' 'r:|=*'
else
zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' 'r:|=*' 'l:|=* r:|=*'
zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' 'r:|=*'
fi
fi
unset CASE_SENSITIVE HYPHEN_INSENSITIVE