]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0840: [security]: code injection in netrw via bookmarks v9.2.0840
authorYasuhiro Matsumoto <mattn.jp@gmail.com>
Mon, 6 Jul 2026 04:54:03 +0000 (13:54 +0900)
committerChristian Brabandt <cb@256bit.org>
Thu, 23 Jul 2026 19:56:55 +0000 (19:56 +0000)
Problem:  [security]: code injection in netrw via bookmarks and history
          (David Carliez)
Solution: Escape the '|' explicitly (Yasuhiro Matsumoto)

The bookmark and history menu builders interpolate paths into :execute'd
:menu commands using g:netrw_menu_escape, which did not escape the Ex
command separator '|'. A crafted path could break out of the :menu command
and run arbitrary Ex/shell commands when the menu was built or triggered.

Add '|' to g:netrw_menu_escape for the menu names, escape the :e right-hand
side with fnameescape(), and quote the netrw#MakeTgt() argument with
string() instead of raw single-quote interpolation.

Github Security Advisory:
https://github.com/vim/vim/security/advisories/GHSA-rcr7-f3wr-22r2

Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/pack/dist/opt/netrw/autoload/netrw.vim
src/version.c

index 64b5ce3aaf91dd761b1f62bd738993ef331a551e..d745fd36fada651bc34427e4255f69b8daf62b0c 100644 (file)
@@ -1,7 +1,7 @@
 " Creator:    Charles E Campbell
 " Previous Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
 " Maintainer: This runtime file is looking for a new maintainer.
-" Last Change: 2026 Jul 22
+" Last Change: 2026 Jul 23
 " Copyright:  Copyright (C) 2016 Charles E. Campbell {{{1
 "             Permission is hereby granted to use and distribute this code,
 "             with or without modifications, provided that this copyright
@@ -375,7 +375,7 @@ if has("win32")
 else
   call s:NetrwInit("g:netrw_glob_escape",'*[]?`{~$\')
 endif
-call s:NetrwInit("g:netrw_menu_escape",'.&? \')
+call s:NetrwInit("g:netrw_menu_escape",'.&? \|')
 call s:NetrwInit("s:netrw_map_escape","<|\n\r\\\<C-V>\"")
 if has("gui_running") && (&enc == 'utf-8' || &enc == 'utf-16' || &enc == 'ucs-4')
   let s:treedepthstring= "│ "
@@ -3777,13 +3777,14 @@ function s:NetrwBookmarkMenu()
         if exists("g:netrw_bookmarklist") && g:netrw_bookmarklist != [] && g:netrw_dirhistmax > 0
             let cnt= 1
             for bmd in g:netrw_bookmarklist
-                let bmd= escape(bmd,g:netrw_menu_escape)
+                let ebmd= escape(bmd,g:netrw_menu_escape)
+                let fbmd= escape(fnameescape(bmd),'|')
 
                 " show bookmarks for goto menu
-                exe 'sil! menu '.g:NetrwMenuPriority.".2.".cnt." ".g:NetrwTopLvlMenu.'Bookmarks.'.bmd.'    :e '.bmd."\<cr>"
+                exe 'sil! menu '.g:NetrwMenuPriority.".2.".cnt." ".g:NetrwTopLvlMenu.'Bookmarks.'.ebmd.'    :e '.fbmd."\<cr>"
 
                 " show bookmarks for deletion menu
-                exe 'sil! menu '.g:NetrwMenuPriority.".8.2.".cnt." ".g:NetrwTopLvlMenu.'Bookmarks\ and\ History.Bookmark\ Delete.'.bmd.'   '.cnt."mB"
+                exe 'sil! menu '.g:NetrwMenuPriority.".8.2.".cnt." ".g:NetrwTopLvlMenu.'Bookmarks\ and\ History.Bookmark\ Delete.'.ebmd.'   '.cnt."mB"
                 let cnt= cnt + 1
             endfor
 
@@ -3799,7 +3800,8 @@ function s:NetrwBookmarkMenu()
                 let priority = g:netrw_dirhistcnt + histcnt
                 if exists("g:netrw_dirhist_{cnt}")
                     let histdir= escape(g:netrw_dirhist_{cnt},g:netrw_menu_escape)
-                    exe 'sil! menu '.g:NetrwMenuPriority.".3.".priority." ".g:NetrwTopLvlMenu.'History.'.histdir.'    :e '.histdir."\<cr>"
+                    let ehistdir= escape(fnameescape(g:netrw_dirhist_{cnt}),'|')
+                    exe 'sil! menu '.g:NetrwMenuPriority.".3.".priority." ".g:NetrwTopLvlMenu.'History.'.histdir.'    :e '.ehistdir."\<cr>"
                 endif
                 let first = 0
                 let cnt   = ( cnt - 1 ) % g:netrw_dirhistmax
@@ -7152,7 +7154,7 @@ function s:NetrwTgtMenu()
                 let tgtdict[bmd]= cnt
                 let ebmd= escape(bmd,g:netrw_menu_escape)
                 " show bookmarks for goto menu
-                exe 'sil! menu <silent> '.g:NetrwMenuPriority.".19.1.".cnt." ".g:NetrwTopLvlMenu.'Targets.'.ebmd." :call netrw#MakeTgt('".bmd."')\<cr>"
+                exe 'sil! menu <silent> '.g:NetrwMenuPriority.".19.1.".cnt." ".g:NetrwTopLvlMenu.'Targets.'.ebmd." :call netrw#MakeTgt(".escape(string(bmd),'|').")\<cr>"
                 let cnt= cnt + 1
             endfor
         endif
@@ -7170,7 +7172,7 @@ function s:NetrwTgtMenu()
                     endif
                     let tgtdict[histentry] = histcnt
                     let ehistentry         = escape(histentry,g:netrw_menu_escape)
-                    exe 'sil! menu <silent> '.g:NetrwMenuPriority.".19.2.".priority." ".g:NetrwTopLvlMenu.'Targets.'.ehistentry."     :call netrw#MakeTgt('".histentry."')\<cr>"
+                    exe 'sil! menu <silent> '.g:NetrwMenuPriority.".19.2.".priority." ".g:NetrwTopLvlMenu.'Targets.'.ehistentry."     :call netrw#MakeTgt(".escape(string(histentry),'|').")\<cr>"
                 endif
                 let histcnt = histcnt + 1
             endwhile
index 9d3c95b005b26fe8da0792a706d9d26c4accd098..75110ae0ab5ca7b4ff581fbde30d58166f3ebcbf 100644 (file)
@@ -758,6 +758,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    840,
 /**/
     839,
 /**/