patch 9.2.0421: vimball: can smuggle Vimscript into VimballRecord file
Commit:
https://github.com/vim/vim/commit/77499e009af677720e747debebedb78d12a77cb6
Author: Christian Brabandt <
c...@256bit.org>
Date: Wed Apr 29 20:36:14 2026 +0000
patch 9.2.0421: vimball: can smuggle Vimscript into VimballRecord file
Problem: vimball: can smuggle Vimscript into VimballRecord file
(Mayank Jangid and Kushal Khemka)
Solution: Disallow strange file names
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/runtime/autoload/vimball.vim b/runtime/autoload/vimball.vim
index 8cc206f1d..3afd8e6c0 100644
--- a/runtime/autoload/vimball.vim
+++ b/runtime/autoload/vimball.vim
@@ -103,14 +103,14 @@ fun! vimball#MkVimball(line1,line2,writelevel,...) range
while linenr <= a:line2
let svfile = getline(linenr)
-
+
if !filereadable(svfile)
call vimball#ShowMesg(s:ERROR,"unable to read file<".svfile.">")
call s:ChgDir(curdir)
call vimball#RestoreSettings()
return
endif
-
+
" create/switch to mkvimball tab
if !exists("vbtabnr")
tabnew
@@ -119,7 +119,7 @@ fun! vimball#MkVimball(line1,line2,writelevel,...) range
else
exe "tabn ".vbtabnr
endif
-
+
let lastline= line("$") + 1
if lastline == 2 && getline("$") == ""
call setline(1,'" Vimball Archiver by Charles E. Campbell')
@@ -163,7 +163,7 @@ endfun
" ---------------------------------------------------------------------
" vimball#Vimball: extract and distribute contents from a vimball {{{2
-" (invoked the the UseVimball command embedded in
+" (invoked the the UseVimball command embedded in
" vimballs' prologue)
fun! vimball#Vimball(really,...)
@@ -213,7 +213,7 @@ fun! vimball#Vimball(really,...)
" give title to listing of (extracted) files from Vimball Archive
if a:really
echohl Title | echomsg "Vimball Archive" | echohl None
- else
+ else
echohl Title | echomsg "Vimball Archive Listing" | echohl None
echohl Statement | echomsg "files would be placed under: ".home | echohl None
endif
@@ -237,6 +237,15 @@ fun! vimball#Vimball(really,...)
bw! Vimball
call s:ChgDir(curdir)
return
+ " Also, disallow strange paths, that could lead to code execution from
+ " .VimballRecord
+ " Disallow: pipe, quotes and closing paren
+ elseif fname =~ '[|'')"]'
+ echomsg printf("(Vimball) Forbidding strange filename: '%s', aborting...", fname)
+ exe "tabn ".curtabnr
+ bw! Vimball
+ call s:ChgDir(curdir)
+ return
endif
if a:really
@@ -295,7 +304,7 @@ fun! vimball#Vimball(really,...)
exe "silent w! ".fnameescape(fnamepath)
endif
echo "wrote ".fnameescape(fnamepath)
- call s:RecordInVar(home,"call delete('".fnamepath."')")
+ call s:RecordInVar(home,"call delete('".escape(fnamepath, '"''|')."')")
endif
" return to tab with vimball
@@ -370,7 +379,7 @@ fun! vimball#RmVimball(...)
call s:ChgDir(home)
if filereadable(".VimballRecord")
- keepalt keepjumps 1split
+ keepalt keepjumps 1split
sil! keepalt keepjumps e .VimballRecord
let keepsrch= @/
if search('^\M'.curfile."\m: ".'cw')
@@ -558,7 +567,7 @@ fun! s:RecordInFile(home)
if exists("s:recordfile") || exists("s:recorddir")
let curdir= getcwd()
call s:ChgDir(a:home)
- keepalt keepjumps 1split
+ keepalt keepjumps 1split
let cmd= expand("%:tr").": "
diff --git a/src/testdir/test_plugin_vimball.vim b/src/testdir/test_plugin_vimball.vim
index ab740d1d2..30093ef71 100644
--- a/src/testdir/test_plugin_vimball.vim
+++ b/src/testdir/test_plugin_vimball.vim
@@ -97,3 +97,16 @@ func Test_vimball_path_traversal_drive_letter()
call assert_match('(Vimball) Path Traversal Attack detected, aborting\.\.\.', mess)
call s:teardown()
endfunc
+
+func Test_vimball_evil_filenames()
+ call s:Mkvimball()
+ call delete('XVimball', 'rf')
+ sp Xtest.vmb
+ 4s#XVimball#pwn')#
+ so %
+ call feedkeys("\<cr>", "it")
+
+ let mess = execute(':mess')->split('
')[-1]
+ call assert_match('(Vimball) Forbidding strange filename:.* aborting\.\.\.', mess)
+ call s:teardown()
+endfunc
diff --git a/src/version.c b/src/version.c
index 699db3c56..11ae9897a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 421,
/**/
420,
/**/