diff --git a/runtime/ftplugin/cucumber.vim b/runtime/ftplugin/cucumber.vim index f4848d1c60..9723898d15 100644 --- a/runtime/ftplugin/cucumber.vim +++ b/runtime/ftplugin/cucumber.vim @@ -2,6 +2,8 @@ " Language: Cucumber " Maintainer: Tim Pope " Last Change: 2016 Aug 29 +" 2026 May 26 by Vim Project: prevent Code Injection +" https://github.com/vim/vim/security/advisories/GHSA-4473-94jm-w5x9 " Only do this when not done yet for this buffer if (exists("b:did_ftplugin")) @@ -96,7 +98,8 @@ function! s:stepmatch(receiver,target) catch endtry if has("ruby") && pattern !~ '\\\@ " Last Change: 2025 Jan 19 +" 2026 May 17 by Vim Project: add 'suffixesadd' #20197 " Credits: The original author, Noah Bogart " Only do this when not done yet for this buffer @@ -13,5 +14,6 @@ let b:did_ftplugin = 1 setlocal iskeyword+=- setlocal comments=n:# setlocal commentstring=#\ %s +setlocal suffixesadd=.just -let b:undo_ftplugin = "setlocal iskeyword< comments< commentstring<" +let b:undo_ftplugin = "setlocal iskeyword< comments< commentstring< suffixesadd<" diff --git a/runtime/pack/dist/opt/netrw/autoload/netrw.vim b/runtime/pack/dist/opt/netrw/autoload/netrw.vim index 61c7ecf754..e82e695e18 100644 --- a/runtime/pack/dist/opt/netrw/autoload/netrw.vim +++ b/runtime/pack/dist/opt/netrw/autoload/netrw.vim @@ -1,7 +1,7 @@ " Creator: Charles E Campbell " Previous Maintainer: Luca Saccarola " Maintainer: This runtime file is looking for a new maintainer. -" Last Change: 2026 May 14 +" Last Change: 2026 May 17 " 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 @@ -2935,7 +2935,7 @@ function s:NetrwBookHistSave() while ( first || cnt != g:netrw_dirhistcnt ) let lastline= lastline + 1 if exists("g:netrw_dirhist_{cnt}") - call setline(lastline,'let g:netrw_dirhist_'.cnt."='".g:netrw_dirhist_{cnt}."'") + call setline(lastline,'let g:netrw_dirhist_'.cnt.'='.string(g:netrw_dirhist_{cnt})) endif let first = 0 let cnt = ( cnt - 1 ) % g:netrw_dirhistmax @@ -4413,10 +4413,10 @@ endfunction " s:NetrwHome: this function determines a "home" for saving bookmarks and history {{{2 function s:NetrwHome() - if has('nvim') - let home = netrw#fs#PathJoin(stdpath('state'), 'netrw') - elseif exists('g:netrw_home') + if exists('g:netrw_home') let home = expand(g:netrw_home) + elseif has('nvim') + let home = netrw#fs#PathJoin(stdpath('state'), 'netrw') elseif exists('$MYVIMDIR') let home = expand('$MYVIMDIR')->substitute('/$', '', '') else diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim index 41570cce4f..044f2a9e3e 100644 --- a/runtime/syntax/sh.vim +++ b/runtime/syntax/sh.vim @@ -3,30 +3,7 @@ " Maintainer: This runtime file is looking for a new maintainer. " Previous Maintainers: Charles E. Campbell " Lennart Schultz -" Last Change: 2024 Mar 04 by Vim Project {{{1 -" 2024 Nov 03 by Aliaksei Budavei <0x000c70 AT gmail DOT com> improved bracket expressions, #15941 -" 2025 Jan 06 add $PS0 to bashSpecialVariables #16394 -" 2025 Jan 18 add bash coproc, remove duplicate syn keywords #16467 -" 2025 Mar 21 update shell capability detection #16939 -" 2025 Apr 03 command substitution opening paren at EOL #17026 -" 2025 Apr 10 improve shell detection #17084 -" 2025 Apr 29 match escaped chars in test operands #17221 -" 2025 May 06 improve single-quote string matching in parameter expansions -" 2025 May 06 match KornShell compound arrays -" 2025 May 10 improve wildcard character class lists -" 2025 May 21 improve supported KornShell features -" 2025 Jun 16 change how sh_fold_enabled is reset #17557 -" 2025 Jul 18 properly delete :commands #17785 -" 2025 Aug 23 bash: add support for ${ cmd;} and ${|cmd;} #18084 -" 2025 Sep 23 simplify ksh logic, update sh statements #18355 -" 2026 Jan 15 highlight command switches that contain a digit -" 2026 Feb 11 improve support for KornShell function names and variables -" 2026 Feb 15 improve comment handling #19414 -" 2026 Mar 23 improve matching of function definitions #19638 -" 2026 Apr 02 improve matching of function definitions #19849 -" 2026 Apr 19 improve detection of special variables #20016 -" 2026 May 14 don't highlight parens as part of the function name #20219 -" }}} +" Last Change: 2026 May 17 by Vim Project " Version: 208 " Former URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_SH " For options and settings, please use: :help ft-sh-syntax @@ -281,7 +258,7 @@ syn cluster shDerefList contains=shDeref,shDerefSimple,shDerefVar,shDerefSpecial syn cluster shDerefVarList contains=shDerefOffset,shDerefOp,shDerefVarArray,shDerefOpError syn cluster shEchoList contains=shArithmetic,shBracketExpr,shCommandSub,shCommandSubBQ,shDerefVarArray,shSubshare,shValsub,shDeref,shDerefSimple,shEscape,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shCtrlSeq,shEchoQuote syn cluster shExprList1 contains=shBracketExpr,shNumber,shOperator,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shExpr,shDblBrace,shDeref,shDerefSimple,shCtrlSeq -syn cluster shExprList2 contains=@shExprList1,@shCaseList,shTest +syn cluster shExprList2 contains=@shExprList1,@shCaseList,shTest,shFunctionNameError syn cluster shFunctionCmds contains=shFor,shCaseEsac,shIf,shRepeat,shDblBrace,shDblParen if exists("b:is_ksh88") || exists("b:is_mksh") " Offer "shFunctionCmds" as is. @@ -307,7 +284,7 @@ if exists("b:is_kornshell") || exists("b:is_bash") endif syn cluster shPPSLeftList contains=shAlias,shArithmetic,shBracketExpr,shCmdParenRegion,shCommandSub,shSubshare,shValsub,shCtrlSeq,shDeref,shDerefSimple,shDoubleQuote,shEcho,shEscape,shExDoubleQuote,shExpr,shExSingleQuote,shHereDoc,shNumber,shOperator,shOption,shPosnParm,shHereString,shRedir,shSingleQuote,shSpecial,shStatement,shSubSh,shTest,shVariable syn cluster shPPSRightList contains=shDeref,shDerefSimple,shEscape,shPosnParm -syn cluster shSubShList contains=shBracketExpr,@shCommandSubList,shCommandSubBQ,shSubshare,shValsub,shCaseEsac,shColon,shCommandSub,shComment,shDo,shEcho,shExpr,shFor,shIf,shHereString,shRedir,shSetList,shSource,shStatement,shVariable,shCtrlSeq,shOperator +syn cluster shSubShList contains=shBracketExpr,@shCommandSubList,shCommandSubBQ,shSubshare,shValsub,shCaseEsac,shColon,shCommandSub,shComment,shDo,shEcho,shExpr,shFor,shIf,shHereString,shRedir,shSetList,shSource,shStatement,shVariable,shCtrlSeq,shOperator,shFunctionNameError syn cluster shTestList contains=shArithmetic,shBracketExpr,shCommandSub,shCommandSubBQ,shSubshare,shValsub,shCtrlSeq,shDeref,shDerefSimple,shDoubleQuote,shSpecialDQ,shExDoubleQuote,shExpr,shExSingleQuote,shNumber,shOperator,shSingleQuote,shTest,shTestOpr syn cluster shNoZSList contains=shSpecialNoZS syn cluster shForList contains=shTestOpr,shNumber,shDerefSimple,shDeref,shCommandSub,shCommandSubBQ,shSubshare,shValsub,shArithmetic @@ -676,6 +653,12 @@ if exists("b:is_bash") syn match shFunctionTwo "\%#=1\%(\%(\<\k\+\|[^()<>|&$;\t ]\+\)\+\)\@>\ze\s*\%(()\ze\)\=\_s*{" contained skipwhite skipnl nextgroup=shFunctionExpr contains=shFunctionParens syn match shFunctionThree "\%#=1^\s*\zs\%(\%(\<\k\+\|[^()<>|&$;\t ]\+\)\+\)\@>\s*()\ze\_s*((\@!" skipwhite skipnl nextgroup=shFunctionSubSh contains=shFunctionParens syn match shFunctionFour "\%#=1\%(\%(\<\k\+\|[^()<>|&$;\t ]\+\)\+\)\@>\ze\s*\%(\%(()\ze\)\=\)\@>\_s*((\@!" contained skipwhite skipnl nextgroup=shFunctionSubSh contains=shFunctionParens + " Claim empty array assignments. + syn match shArrayEmptyDecl "\%#=1\ze\%(\<\h\w*=\)\@>()" transparent nextgroup=shVariable + + if !exists("g:sh_no_error") + syn match shFunctionNameError "\%#=1\%(\%(\<\h\w*\)\@>=\)\%(\%(\w\+\)\@>=\=\)\+()" skipwhite skipnl nextgroup=shExpr,shSubSh + endif elseif exists("b:is_ksh88") " AT&T ksh88 syn match shFunctionCmdOne "^\s*\zs\h\w*\s*()\ze\_s*\%(\%(for\|case\|select\|if\|while\|until\)\>\|\[\[\s\|((\)" skipwhite skipnl nextgroup=@shFunctionCmds contains=shFunctionParens @@ -970,6 +953,9 @@ if !exists("skip_sh_syntax_inits") hi def link shInError Error hi def link shParenError Error hi def link shTestError Error + if exists("b:is_bash") + hi def link shFunctionNameError Error + endif if exists("b:is_kornshell") || exists("b:is_posix") hi def link shDTestError Error endif diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index c4a301c6f0..a74fd74728 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -3463,4 +3463,34 @@ func Test_app_file() filetype off endfunc +func Test_cucumber_code_injection() + CheckFeature ruby + filetype plugin on + + call mkdir('Xcucu/features/step_definitions', 'pR') + call writefile([ + \ 'Feature: demo', + \ ' Scenario: trigger', + \ ' Given xyzzy', + \ ], 'Xcucu/features/test.feature') + let marker = getcwd() . '/Xcucu/MARKER' + " Malicious step: terminates the regex literal, injects Ruby system(), + " comments the trailing slash. With the fix, the pattern is passed to + " Regexp.new() instead of Kernel.eval() and the payload is inert. + call writefile([ + \ 'Given /xyzzy/; system("touch ' . marker . '"); #/ do', + \ 'end', + \ ], 'Xcucu/features/step_definitions/poc.rb') + + new Xcucu/features/test.feature + call assert_equal('cucumber', &filetype) + call cursor(3, 1) + " Triggers s:jump -> s:steps -> s:stepmatch on every discovered step, + " including the malicious one. Suppress preview and error messages. + silent! normal [d + call assert_false(filereadable(marker), 'Ruby injection executed') + bwipe! + filetype plugin off +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_plugin_netrw.vim b/test/old/testdir/test_plugin_netrw.vim index ca8746a590..0d206b55cc 100644 --- a/test/old/testdir/test_plugin_netrw.vim +++ b/test/old/testdir/test_plugin_netrw.vim @@ -767,4 +767,24 @@ function Test_netrw_NetrwMaps_CR_dirname() unlet! g:netrw_pwn bw! endfunction + +func Test_netrw_injection() + let g:netrw_home = getcwd() + let savefile = g:netrw_home . '/.netrwhist' + let g:netrw_dirhistmax = 10 + let g:netrw_dirhistcnt = 1 + let g:netrw_dirhist_1 = "x'|let g:injected = 1|let y='z" + call delete(savefile) + try + call netrw#Call('NetrwBookHistSave') + call assert_true(filereadable(savefile), savefile . ' must be written') + unlet g:netrw_dirhist_1 + execute 'source ' . fnameescape(savefile) + call assert_false(exists("g:injected"), 'injected statement must not execute') + call assert_equal("x'|let g:injected = 1|let y='z", g:netrw_dirhist_1, 'dirname must round-trip') + finally + call delete(savefile) + unlet! g:netrw_home g:netrw_dirhistmax g:netrw_dirhistcnt g:netrw_dirhist_1 g:injected + endtry +endfunc " vim:ts=8 sts=2 sw=2 et