From 0e07b2a1e271f01f3458185876f8712d97f6cf38 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 16 Apr 2026 11:11:29 +0800 Subject: [PATCH] vim-patch:9.2.0357: [security]: command injection via backticks in tag files (#39102) Problem: [security]: command injection via backticks in tag files (Srinivas Piskala Ganesh Babu, Andy Ngo) Solution: Disallow backticks before attempting to expand filenames. Github Advisory: https://github.com/vim/vim/security/advisories/GHSA-cwgx-gcj7-6qh8 Supported by AI https://github.com/vim/vim/commit/c78194e41d5a0b05b0ddf383b6679b1503f977fb Co-authored-by: Christian Brabandt --- src/nvim/tag.c | 4 +++- test/old/testdir/test_tagjump.vim | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 6a46f0a5fe..9c037af73b 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -3076,7 +3076,9 @@ static char *expand_tag_fname(char *fname, char *const tag_fname, const bool exp expand_T xpc; // Expand file name (for environment variables) when needed. - if (expand && path_has_wildcard(fname)) { + // Disallow backticks, they could execute arbitrary shell + // commands. This is not needed for tag filenames. + if (expand && path_has_wildcard(fname) && vim_strchr(fname, '`') == NULL) { ExpandInit(&xpc); xpc.xp_context = EXPAND_FILES; expanded_fname = ExpandOne(&xpc, fname, NULL, diff --git a/test/old/testdir/test_tagjump.vim b/test/old/testdir/test_tagjump.vim index 4216025cac..2d6ef245c9 100644 --- a/test/old/testdir/test_tagjump.vim +++ b/test/old/testdir/test_tagjump.vim @@ -1729,4 +1729,26 @@ func Test_tag_excmd_with_nostartofline() set startofline& endfunc +" Test that backtick expressions in tag filenames are not expanded. +" This prevents command injection via malicious tags files. +func Test_tag_backtick_filename_not_expanded() + let pwned_file = 'Xtags_pwnd' + call assert_false(filereadable(pwned_file)) + + let tagline = "main\t`touch " .. pwned_file .. "`\t/^int main/;\"\tf" + call writefile([tagline], 'Xbt_tags', 'D') + call writefile(['int main(int argc, char **argv) {', '}'], 'Xbt_main.c', 'D') + + set tags=Xbt_tags + sp Xbt_main.c + + " The :tag command should fail to find the file, but must NOT execute + " the backtick shell command. + call assert_fails('tag main', 'E429:') + call assert_false(filereadable(pwned_file)) + + set tags& + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab