patch 9.2.0073: [security]: possible command injection using netrw

Commit: 
https://github.com/vim/vim/commit/79348dbbc09332130f4c86045e1541d68514fcc1
Author: Christian Brabandt <[email protected]>
Date:   Sun Feb 22 21:24:48 2026 +0000

    patch 9.2.0073: [security]: possible command injection using netrw
    
    Problem:  [security]: Insufficient validation of hostname and port in
              netrw URIs allows command injection via shell metacharacters
              (ehdgks0627, un3xploitable).
    Solution: Implement stricter RFC1123 hostname and IP validation.
              Use shellescape() for the provided hostname and port.
    
    Github Advisory:
    https://github.com/vim/vim/security/advisories/GHSA-m3xh-9434-g336
    
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/pack/dist/opt/netrw/autoload/netrw.vim 
b/runtime/pack/dist/opt/netrw/autoload/netrw.vim
index 51e05f2b1..25ca4e8a1 100644
--- a/runtime/pack/dist/opt/netrw/autoload/netrw.vim
+++ b/runtime/pack/dist/opt/netrw/autoload/netrw.vim
@@ -20,6 +20,7 @@
 " 2026 Jan 19 by Vim Project do not create swapfiles #18854
 " 2026 Feb 15 by Vim Project fix global variable initialization for MS-Windows 
#19287
 " 2026 Feb 21 by Vim Project better absolute path detection on MS-Windows 
#19477
+" 2026 Feb 27 by Vim Project Make the hostname validation more strict
 " 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
@@ -2591,13 +2592,26 @@ endfunction
 
 " s:NetrwValidateHostname:  Validate that the hostname is valid {{{2
 " Input:
-"   hostname
+"   hostname, may include an optional username, e.g. user@hostname
+"   allow a alphanumeric hostname or an IPv(4/6) address
 " Output:
 "  true if g:netrw_machine is valid according to RFC1123 #Section 2
 function s:NetrwValidateHostname(hostname)
-    " RFC1123#section-2 mandates, a valid hostname starts with letters or 
digits
-    " so reject everyhing else
-    return a:hostname =~? '^[a-z0-9]'
+  " Username:
+  let user_pat = '\%([a-zA-Z0-9._-]\+@\)\?'
+  " Hostname: 1-64 chars, alphanumeric/dots/hyphens.
+  " No underscores. No leading/trailing dots/hyphens.
+  let host_pat = '[a-zA-Z0-9]\%([-a-zA-Z0-9.]{,62}[a-zA-Z0-9]\)\?$'
+
+  " IPv4: 1-3 digits separated by dots
+  let ipv4_pat = '\%(\d\{1,3}\.\)\{3\}\d\{1,3\}$'
+
+  " IPv6: Hex, colons, and optional brackets
+  let ipv6_pat = '\[\?\%([a-fA-F0-9:]\{2,}\)\+\]\?$'
+
+  return a:hostname =~? '^'.user_pat.host_pat ||
+       \ a:hostname =~? '^'.user_pat.ipv4_pat ||
+       \ a:hostname =~? '^'.user_pat.ipv6_pat
 endfunction
 
 " NetUserPass: set username and password for subsequent ftp transfer {{{2
@@ -8961,15 +8975,15 @@ endfunction
 " s:MakeSshCmd: transforms input command using USEPORT HOSTNAME into {{{2
 "               a correct command for use with a system() call
 function s:MakeSshCmd(sshcmd)
-    if s:user == ""
-        let sshcmd = substitute(a:sshcmd,'\<HOSTNAME\>',s:machine,'')
-    else
-        let sshcmd = 
substitute(a:sshcmd,'\<HOSTNAME\>',s:user."@".s:machine,'')
+    let machine = shellescape(s:machine, 1)
+    if s:user != ''
+        let machine    = shellescape(s:user, 1).'@'.machine
     endif
+    let sshcmd = substitute(a:sshcmd,'\<HOSTNAME\>',machine,'')
     if exists("g:netrw_port") && g:netrw_port != ""
-        let sshcmd= substitute(sshcmd,"USEPORT",g:netrw_sshport.' 
'.g:netrw_port,'')
+        let sshcmd= substitute(sshcmd,"USEPORT",g:netrw_sshport.' 
'.shellescape(g:netrw_port,1),'')
     elseif exists("s:port") && s:port != ""
-        let sshcmd= substitute(sshcmd,"USEPORT",g:netrw_sshport.' '.s:port,'')
+        let sshcmd= substitute(sshcmd,"USEPORT",g:netrw_sshport.' 
'.shellescape(s:port,1),'')
     else
         let sshcmd= substitute(sshcmd,"USEPORT ",'','')
     endif
diff --git a/src/testdir/test_plugin_netrw.vim 
b/src/testdir/test_plugin_netrw.vim
index 23a060227..99dba4b96 100644
--- a/src/testdir/test_plugin_netrw.vim
+++ b/src/testdir/test_plugin_netrw.vim
@@ -291,7 +291,7 @@ func Test_netrw_parse_special_char_user()
   call assert_equal(result.path, 'test.txt')
 endfunction
 
-func Test_netrw_wipe_empty_buffer_fastpath()
+func Test_netrw_empty_buffer_fastpath_wipe()
   " SetUp() may have opened some buffers
   let previous = bufnr('$')
   let g:netrw_fastbrowse=0
@@ -560,4 +560,10 @@ func Test_netrw_filemove_pwsh()
   call s:test_netrw_filemove()
 endfunc
 
+func Test_netrw_reject_evil_hostname()
+  let msg = execute(':e scp://x;touch RCE;x/dir/')
+  let msg = split(msg, "
")[-1]
+  call assert_match('Rejecting invalid hostname', msg)
+endfunction
+
 " vim:ts=8 sts=2 sw=2 et
diff --git a/src/version.c b/src/version.c
index 11467caea..3d969453b 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 */
+/**/
+    73,
 /**/
     72,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1vw5At-00GEr9-H9%40256bit.org.

Raspunde prin e-mail lui