From 5f4ed6bb9cfc951993d9c5ca2e944e657957f9f1 Mon Sep 17 00:00:00 2001 From: Hirohito Higashi Date: Fri, 26 Jun 2026 20:07:01 +0900 Subject: [PATCH] patch 9.2.0736: potential command execution in PHP omni-completion Problem: With PHP omni-completion, a crafted file can potentially execute arbitrary commands when completing a class member. Solution: Quote the class name before inserting it into the search() pattern run via win_execute(). Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Hirohito Higashi Signed-off-by: Christian Brabandt --- runtime/autoload/phpcomplete.vim | 3 ++- src/testdir/Make_all.mak | 2 ++ src/testdir/test_plugin_phpcomplete.vim | 35 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/testdir/test_plugin_phpcomplete.vim diff --git a/runtime/autoload/phpcomplete.vim b/runtime/autoload/phpcomplete.vim index 5b4263ae4..93f7d8b45 100644 --- a/runtime/autoload/phpcomplete.vim +++ b/runtime/autoload/phpcomplete.vim @@ -2082,7 +2082,8 @@ function! phpcomplete#GetClassContentsStructure(file_path, file_lines, class_nam let result = [] let popup_id = popup_create(a:file_lines, {'hidden': v:true}) - call win_execute(popup_id, 'call search(''\c\(class\|interface\|trait\)\_s\+'.a:class_name.'\(\>\|$\)'')') + call win_execute(popup_id, 'call search(' + \ . string('\c\(class\|interface\|trait\)\_s\+' . a:class_name . '\(\>\|$\)') . ')') call win_execute(popup_id, "let cfline = line('.')") call win_execute(popup_id, "call search('{')") call win_execute(popup_id, "let endline = line('.')") diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 49c034fb3..b362bbbfb 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -229,6 +229,7 @@ NEW_TESTS = \ test_perl \ test_plugin_ccomplete \ test_plugin_netrw \ + test_plugin_phpcomplete \ test_plugin_python3complete \ test_plugin_tar \ test_plus_arg_edit \ @@ -482,6 +483,7 @@ NEW_TESTS_RES = \ test_perl.res \ test_plugin_ccomplete.res \ test_plugin_netrw.res \ + test_plugin_phpcomplete.res \ test_plugin_python3complete.res \ test_plugin_tar.res \ test_plus_arg_edit.res \ diff --git a/src/testdir/test_plugin_phpcomplete.vim b/src/testdir/test_plugin_phpcomplete.vim new file mode 100644 index 000000000..7f66be47b --- /dev/null +++ b/src/testdir/test_plugin_phpcomplete.vim @@ -0,0 +1,35 @@ +" Tests for the PHP omni-completion plugin (runtime/autoload/phpcomplete.vim). + +" A buffer class name is interpolated into a search() pattern run via +" win_execute(). Without escaping, "'" closes the string and "|" starts a new +" Ex command, so the name runs as an Ex command during completion. +func Test_phpcomplete_no_exec_via_class_name() + unlet! g:phpcomplete_injected + let lines = [' 0, 'no class structure returned') + call assert_match('class Foo', result[0].content, + \ 'class body missing from returned content') + call assert_match('bar', result[0].content, + \ 'class member missing from returned content') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab