From: Christian Brabandt Date: Sun, 5 Apr 2026 15:58:00 +0000 (+0000) Subject: patch 9.2.0299: runtime(zip): may write using absolute paths X-Git-Tag: v9.2.0299^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=46f530e517bd1b59acc2eb0d2aa76d02e54ca9fe;p=thirdparty%2Fvim.git patch 9.2.0299: runtime(zip): may write using absolute paths Problem: runtime(zip): may write using absolute paths (syndicate) Solution: Detect this case and abort on Unix, warn in the documentation about possible issues Signed-off-by: Christian Brabandt --- diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim index 1ce9cfc2f7..f4482fd7fc 100644 --- a/runtime/autoload/zip.vim +++ b/runtime/autoload/zip.vim @@ -21,6 +21,7 @@ " 2026 Feb 08 by Vim Project: use system() instead of :! " 2026 Mar 08 by Vim Project: Make ZipUpdatePS() check for powershell " 2026 Apr 01 by Vim Project: Detect more path traversal attacks +" 2026 Apr 05 by Vim Project: Detect more path traversal attacks " License: Vim License (see vim's :help license) " Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1 " Permission is hereby granted to use and distribute this code, @@ -395,9 +396,16 @@ fun! zip#Write(fname) if has("unix") let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','') let fname = substitute(a:fname,'zipfile://.\{-}::\([^\\].*\)$','\1','') + " fname should not start with a leading slash to avoid writing anywhere into the system + if fname =~ '^/' + call s:Mess('Error', "***error*** (zip#Write) Path Traversal Attack detected, not writing!") + call s:ChgDir(curdir,s:WARNING,"(zip#Write) unable to return to ".curdir."!") + return + endif else let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','') let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','') + " TODO: what to check on MS-Windows to avoid writing absolute paths? endif if fname =~ '^[.]\{1,2}/' let gnu_cmd = g:zip_zipcmd . ' -d ' . s:Escape(fnamemodify(zipfile,":p"),0) . ' ' . s:Escape(fname,0) diff --git a/runtime/doc/pi_zip.txt b/runtime/doc/pi_zip.txt index b1bc7fd7dc..e9294b4059 100644 --- a/runtime/doc/pi_zip.txt +++ b/runtime/doc/pi_zip.txt @@ -1,4 +1,4 @@ -*pi_zip.txt* For Vim version 9.2. Last change: 2026 Feb 14 +*pi_zip.txt* For Vim version 9.2. Last change: 2026 Apr 05 +====================+ | Zip File Interface | @@ -33,6 +33,10 @@ Copyright: Copyright (C) 2005-2015 Charles E Campbell *zip-copyright* also write to the file. Currently, one may not make a new file in zip archives via the plugin. + The zip plugin tries to detect some common path traversal attack + patterns, but it may not catch all possible cases. Please be very + careful when using this plugin with untrusted input. + COMMANDS~ *zip-x* x : extract a listed file when the cursor is atop it diff --git a/src/testdir/samples/evil.zip b/src/testdir/samples/evil.zip index 17cffadf93..8361710b9b 100644 Binary files a/src/testdir/samples/evil.zip and b/src/testdir/samples/evil.zip differ diff --git a/src/testdir/test_plugin_zip.vim b/src/testdir/test_plugin_zip.vim index 53b6120834..6d77643482 100644 --- a/src/testdir/test_plugin_zip.vim +++ b/src/testdir/test_plugin_zip.vim @@ -296,3 +296,22 @@ def g:Test_zip_fname_evil_path2() assert_match('zipfile://.*::.*tmp/foobar', @%) bw! enddef + +def g:Test_zip_fname_evil_path3() + CheckNotMSWindows + # needed for writing the zip file + CheckExecutable zip + + CopyZipFile("evil.zip") + defer delete("X.zip") + e X.zip + + :1 + var fname = 'payload.txt' + search('\V' .. fname) + exe "normal \" + :w! + var mess = execute(':mess') + assert_match('Path Traversal Attack', mess) + bw! +enddef diff --git a/src/version.c b/src/version.c index e3dee3b3a5..4d0ec69447 100644 --- a/src/version.c +++ b/src/version.c @@ -734,6 +734,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 299, /**/ 298, /**/