diff --git a/src/tag.c b/src/tag.c index d3e27e6023..0f12e384b5 100644 --- a/src/tag.c +++ b/src/tag.c @@ -4137,8 +4137,10 @@ expand_tag_fname(char_u *fname, char_u *tag_fname, int expand) /* * Expand file name (for environment variables) when needed. + * Disallow backticks, they could execute arbitrary shell + * commands. This is not needed for tag filenames. */ - if (expand && mch_has_wildcard(fname)) + if (expand && mch_has_wildcard(fname) && vim_strchr(fname, '`') == NULL) { ExpandInit(&xpc); xpc.xp_context = EXPAND_FILES; diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim index bbab3c70e8..c0fa7b02e6 100644 --- a/src/testdir/test_tagjump.vim +++ b/src/testdir/test_tagjump.vim @@ -1693,4 +1693,26 @@ func Test_tag_excmd_with_number_vim9script() bwipe! 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 diff --git a/src/version.c b/src/version.c index 0e22232f13..6716d470b3 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 */ +/**/ + 357, /**/ 356, /**/