fix: escape % characters in git prompts

This patch adds missing % character escaping for custom git prompts
used in a few themes. It also includes escaping for git-prompt.sh.

In combination with CVE-2021-45444, this could allow code execution
when displaying branch information in cloned malicious git repositories.
However, zsh 5.8.1 and newer are largely the default zsh versions, and
on those supported distributions with older zsh versions, the CVE has been
found to be also patched.

For this reason, this doesn't qualify as a security patch, but a
bug fix for proper printing of git branches.
This commit is contained in:
Marc Cornellà 2026-05-28 18:57:52 +02:00
commit c90141ed77
11 changed files with 18 additions and 9 deletions

View file

@ -16,7 +16,8 @@ ZSH_THEME_GIT_PROMPT_CLEAN=""
git_custom_status() {
local cb=$(git_current_branch)
if [ -n "$cb" ]; then
echo "$(parse_git_dirty)$ZSH_THEME_GIT_PROMPT_PREFIX$(git_current_branch)$ZSH_THEME_GIT_PROMPT_SUFFIX"
cb="${cb//\%/%%}"
echo "$(parse_git_dirty)$ZSH_THEME_GIT_PROMPT_PREFIX${cb}$ZSH_THEME_GIT_PROMPT_SUFFIX"
fi
}

View file

@ -10,6 +10,7 @@ ZSH_THEME_GIT_PROMPT_CLEAN=""
git_custom_status() {
local branch=$(git_current_branch)
[[ -n "$branch" ]] || return 0
branch="${branch//\%/%%}"
print "%{${fg_bold[yellow]}%}$(work_in_progress)%{$reset_color%}\
${ZSH_THEME_GIT_PROMPT_PREFIX}$(parse_git_dirty)${branch}\
${ZSH_THEME_GIT_PROMPT_SUFFIX}"

View file

@ -31,7 +31,7 @@ function josh_prompt {
prompt=" $prompt"
done
prompt="%{%F{green}%}$PWD$prompt%{%F{red}%}$(ruby_prompt_info)%{$reset_color%} $(git_current_branch)"
prompt="%{%F{green}%}$PWD$prompt%{%F{red}%}$(ruby_prompt_info)%{$reset_color%} ${branch//\%/%%}"
echo $prompt
}

View file

@ -41,4 +41,4 @@ USER_COLOR=$GREEN_BOLD
PROMPT='
%{$USER_COLOR%}%n@%m%{$WHITE%}:%{$YELLOW%}%~%u$(parse_git_dirty)$(git_prompt_ahead)%{$RESET_COLOR%}
%{$BLUE%}>%{$RESET_COLOR%} '
RPROMPT='%{$GREEN_BOLD%}$(git_current_branch)$(git_prompt_short_sha)$(git_prompt_status)%{$RESET_COLOR%}'
RPROMPT='%{$GREEN_BOLD%}${$(git_current_branch)//\%/%%}$(git_prompt_short_sha)$(git_prompt_status)%{$RESET_COLOR%}'

View file

@ -7,7 +7,7 @@ function my_git_prompt_info() {
ref=$(git symbolic-ref HEAD 2> /dev/null) || return
GIT_STATUS=$(git_prompt_status)
[[ -n $GIT_STATUS ]] && GIT_STATUS=" $GIT_STATUS"
echo "$ZSH_THEME_GIT_PROMPT_PREFIX${ref#refs/heads/}$GIT_STATUS$ZSH_THEME_GIT_PROMPT_SUFFIX"
echo "$ZSH_THEME_GIT_PROMPT_PREFIX${${ref#refs/heads/}//\%/%%}$GIT_STATUS$ZSH_THEME_GIT_PROMPT_SUFFIX"
}
PROMPT='%{$fg_bold[green]%}%n@%m%{$reset_color%} %{$fg_bold[blue]%}%2~%{$reset_color%} $(my_git_prompt_info)%{$reset_color%}%B»%b '

View file

@ -42,7 +42,9 @@ function my_git_prompt() {
}
function my_current_branch() {
echo $(git_current_branch || echo "(no branch)")
local branch
branch=$(git_current_branch || echo "(no branch)")
echo "${branch//\%/%%}"
}
function ssh_connection() {

View file

@ -10,6 +10,7 @@ ZSH_THEME_GIT_PROMPT_CLEAN=""
git_custom_status() {
local branch=$(git_current_branch)
[[ -n "$branch" ]] || return 0
branch="${branch//\%/%%}"
echo "$(parse_git_dirty)\
%{${fg_bold[yellow]}%}$(work_in_progress)%{$reset_color%}\
${ZSH_THEME_GIT_PROMPT_PREFIX}${branch}${ZSH_THEME_GIT_PROMPT_SUFFIX}"

View file

@ -31,7 +31,7 @@ git_prompt() {
local cb=$(git_current_branch)
if [[ -n "$cb" ]]; then
local repo_path=$(git_repo_path)
echo " %{$fg_bold[grey]%}$cb %{$fg[white]%}$(git_commit_id)%{$reset_color%}$(git_mode)$(git_dirty)"
echo " %{$fg_bold[grey]%}${cb//\%/%%} %{$fg[white]%}$(git_commit_id)%{$reset_color%}$(git_mode)$(git_dirty)"
fi
}

View file

@ -23,7 +23,8 @@ function mygit() {
if [[ "$(git config --get oh-my-zsh.hide-status)" != "1" ]]; then
ref=$(command git symbolic-ref HEAD 2> /dev/null) || \
ref=$(command git rev-parse --short HEAD 2> /dev/null) || return
echo "$ZSH_THEME_GIT_PROMPT_PREFIX${ref#refs/heads/}$(git_prompt_short_sha)$(git_prompt_status)%{$fg_bold[blue]%}$ZSH_THEME_GIT_PROMPT_SUFFIX "
ref=${${ref#refs/heads/}//\%/%%}
echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref}$(git_prompt_short_sha)$(git_prompt_status)%{$fg_bold[blue]%}${ZSH_THEME_GIT_PROMPT_SUFFIX} "
fi
}

View file

@ -62,7 +62,7 @@ custom_git_prompt_status() {
# get the name of the branch we are on (copied and modified from git.zsh)
function custom_git_prompt() {
ref=$(git symbolic-ref HEAD 2> /dev/null) || return
echo "$ZSH_THEME_GIT_PROMPT_PREFIX${ref#refs/heads/}$(parse_git_dirty)$(git_prompt_ahead)$(custom_git_prompt_status)$ZSH_THEME_GIT_PROMPT_SUFFIX"
echo "$ZSH_THEME_GIT_PROMPT_PREFIX${${ref#refs/heads/}//\%/%%}$(parse_git_dirty)$(git_prompt_ahead)$(custom_git_prompt_status)$ZSH_THEME_GIT_PROMPT_SUFFIX"
}
# %B sets bold text