From c90141ed77ff89cc4d9e957aaee713e576ad2c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Cornell=C3=A0?= Date: Thu, 28 May 2026 18:57:52 +0200 Subject: [PATCH] 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. --- plugins/gitfast/git-prompt.sh | 5 ++++- themes/eastwood.zsh-theme | 3 ++- themes/gallois.zsh-theme | 1 + themes/josh.zsh-theme | 2 +- themes/juanghurtado.zsh-theme | 2 +- themes/lukerandall.zsh-theme | 2 +- themes/mortalscumbag.zsh-theme | 4 +++- themes/oldgallois.zsh-theme | 1 + themes/peepcode.zsh-theme | 2 +- themes/rkj-repos.zsh-theme | 3 ++- themes/sunrise.zsh-theme | 2 +- 11 files changed, 18 insertions(+), 9 deletions(-) diff --git a/plugins/gitfast/git-prompt.sh b/plugins/gitfast/git-prompt.sh index 76ee4ab1..ae508518 100644 --- a/plugins/gitfast/git-prompt.sh +++ b/plugins/gitfast/git-prompt.sh @@ -235,7 +235,7 @@ __git_ps1_show_upstream () if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then upstream="$upstream \${__git_ps1_upstream_name}" else - upstream="$upstream ${__git_ps1_upstream_name}" + upstream="$upstream ${__git_ps1_upstream_name//\%/%%}" # not needed anymore; keep user's # environment clean unset __git_ps1_upstream_name @@ -570,6 +570,9 @@ __git_ps1 () if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then __git_ps1_branch_name=$b b="\${__git_ps1_branch_name}" + else + # escape % in branch name to avoid prompt expansion issues + b="${b//\%/%%}" fi if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then diff --git a/themes/eastwood.zsh-theme b/themes/eastwood.zsh-theme index 31e24fa7..0dd2d42d 100644 --- a/themes/eastwood.zsh-theme +++ b/themes/eastwood.zsh-theme @@ -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 } diff --git a/themes/gallois.zsh-theme b/themes/gallois.zsh-theme index 3fc34907..eb04e66e 100644 --- a/themes/gallois.zsh-theme +++ b/themes/gallois.zsh-theme @@ -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}" diff --git a/themes/josh.zsh-theme b/themes/josh.zsh-theme index df59280d..e8ae18dd 100644 --- a/themes/josh.zsh-theme +++ b/themes/josh.zsh-theme @@ -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 } diff --git a/themes/juanghurtado.zsh-theme b/themes/juanghurtado.zsh-theme index 95a400e6..625f46a3 100644 --- a/themes/juanghurtado.zsh-theme +++ b/themes/juanghurtado.zsh-theme @@ -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%}' diff --git a/themes/lukerandall.zsh-theme b/themes/lukerandall.zsh-theme index cdecd284..d5a452eb 100644 --- a/themes/lukerandall.zsh-theme +++ b/themes/lukerandall.zsh-theme @@ -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 ' diff --git a/themes/mortalscumbag.zsh-theme b/themes/mortalscumbag.zsh-theme index c9994c0f..80c2d70d 100644 --- a/themes/mortalscumbag.zsh-theme +++ b/themes/mortalscumbag.zsh-theme @@ -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() { diff --git a/themes/oldgallois.zsh-theme b/themes/oldgallois.zsh-theme index bb97bfb1..7c77135c 100644 --- a/themes/oldgallois.zsh-theme +++ b/themes/oldgallois.zsh-theme @@ -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}" diff --git a/themes/peepcode.zsh-theme b/themes/peepcode.zsh-theme index 04453461..4010ef1f 100644 --- a/themes/peepcode.zsh-theme +++ b/themes/peepcode.zsh-theme @@ -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 } diff --git a/themes/rkj-repos.zsh-theme b/themes/rkj-repos.zsh-theme index a9fe1a9a..6ce45c96 100644 --- a/themes/rkj-repos.zsh-theme +++ b/themes/rkj-repos.zsh-theme @@ -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 } diff --git a/themes/sunrise.zsh-theme b/themes/sunrise.zsh-theme index 11f6af12..86ae722f 100644 --- a/themes/sunrise.zsh-theme +++ b/themes/sunrise.zsh-theme @@ -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