From bf084967d70ccbdaa8dda49ce3e1fbe2278d4e6e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 6 Apr 2026 10:15:19 +0800 Subject: [PATCH] vim-patch:9.2.0299: runtime(zip): may write using absolute paths (#38810) Problem: runtime(zip): may write using absolute paths (syndicate) Solution: Detect this case and abort on Unix, warn in the documentation about possible issues https://github.com/vim/vim/commit/46f530e517bd1b59acc2eb0d2aa76d02e54ca9fe Co-authored-by: Christian Brabandt (cherry picked from commit 4aa8969d29a1d1060dc00dcf661ec73c110b8533) --- runtime/autoload/zip.vim | 8 ++++++++ runtime/doc/pi_zip.txt | 4 ++++ test/old/testdir/samples/evil.zip | Bin 413 -> 562 bytes test/old/testdir/test_plugin_zip.vim | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim index 473b83ca14..3bf5f701d3 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 b01ba099bf..e3312ea9bc 100644 --- a/runtime/doc/pi_zip.txt +++ b/runtime/doc/pi_zip.txt @@ -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/test/old/testdir/samples/evil.zip b/test/old/testdir/samples/evil.zip index 17cffadf934580090ebe2b3d3876edec14767658..8361710b9bd032d8c4ec094bef18f5884f893fa2 100644 GIT binary patch delta 178 zcmbQsyoqJPUQcEg5e5)&sB4XBm=%#P$iTn=!ZHjD4EiOx1^Q)~x$#w*1^S8lN%{qe zl{xu|DS9OpB?bA(x@krExw?r($r+htsaz9xpNnH;5@E(|9LO3FZeZL^!0-TXRyL4I QW(H;kF-8UkHbxK+06?cIRsaA1 delta 31 kcmdnQGM9P6-pL${XGB=p7#J8Bm>8HC&M+`A>;`cd0D5Kxwg3PC diff --git a/test/old/testdir/test_plugin_zip.vim b/test/old/testdir/test_plugin_zip.vim index 06e60fd7bb..ab26230cc8 100644 --- a/test/old/testdir/test_plugin_zip.vim +++ b/test/old/testdir/test_plugin_zip.vim @@ -297,3 +297,22 @@ func Test_zip_fname_evil_path2() call assert_match('zipfile://.*::.*tmp/foobar', @%) bw! endfunc + +func Test_zip_fname_evil_path3() + CheckNotMSWindows + " needed for writing the zip file + CheckExecutable zip + + call s:CopyZipFile("evil.zip") + defer delete("X.zip") + e X.zip + + :1 + let fname = 'payload.txt' + call search('\V' .. fname) + exe "normal \" + :w! + let mess = execute(':mess') + call assert_match('Path Traversal Attack', mess) + bw! +endfunc