Backport two upstream commits to fix CVE-2026-52858, which allowed arbitrary code execution via python3complete and pythoncomplete omni-completion plugins. Patch 9.2.0561 disables execution of import/from statements in the Python completion plugins by default, adding a g:pythoncomplete_allow_import opt-in variable for users who trust their buffer contents. Patch 9.2.0568 is a follow-up fix that re-imports the vim module inside evalsource() so the opt-in variable check works correctly. CVE: CVE-2026-52858 Upstream patches: -4b850457e1.patch -868ad62cb8.patch Resolves: RHEL-186649 This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent. Assisted-by: Ymir
156 lines
6.1 KiB
Diff
156 lines
6.1 KiB
Diff
From c5bdbe42dccebaf741c9ed6ee32a7c2c75e84dd8 Mon Sep 17 00:00:00 2001
|
|
From: Christian Brabandt <cb@256bit.org>
|
|
Date: Fri, 29 May 2026 19:05:53 +0000
|
|
Subject: [PATCH] patch 9.2.0561: [security]: possible code execution with
|
|
python3complete
|
|
|
|
Problem: [security]: possible code execution with python3complete
|
|
Solution: Disable execution of import/from statements
|
|
|
|
Github Security Advisory:
|
|
https://github.com/vim/vim/security/advisories/GHSA-52mc-rq6p-rc7c
|
|
|
|
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
|
---
|
|
runtime/autoload/README.txt | 1 +
|
|
runtime/autoload/python3complete.vim | 17 ++++++++++++++---
|
|
runtime/autoload/pythoncomplete.vim | 17 ++++++++++++++---
|
|
runtime/doc/filetype.txt | 15 ++++++++++++++-
|
|
4 files changed, 43 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/runtime/autoload/README.txt b/runtime/autoload/README.txt
|
|
--- a/runtime/autoload/README.txt
|
|
+++ b/runtime/autoload/README.txt
|
|
@@ -17,6 +17,7 @@
|
|
javascriptcomplete.vim Javascript
|
|
phpcomplete.vim PHP
|
|
pythoncomplete.vim Python
|
|
+python3complete.vim Python
|
|
rubycomplete.vim Ruby
|
|
syntaxcomplete.vim from syntax highlighting
|
|
xmlcomplete.vim XML (uses files in the xml directory)
|
|
diff --git a/runtime/autoload/python3complete.vim b/runtime/autoload/python3complete.vim
|
|
--- a/runtime/autoload/python3complete.vim
|
|
+++ b/runtime/autoload/python3complete.vim
|
|
@@ -14,6 +14,10 @@
|
|
" i.e. "import url<c-x,c-o>"
|
|
" Continue parsing on invalid line??
|
|
"
|
|
+" v 0.10 by Vim project
|
|
+" * disables importing local modules, unless the global Vim variable
|
|
+" g:pythoncomplete_allow_import is set to non-zero
|
|
+"
|
|
|
|
" v 0.9
|
|
" * Fixed docstring parsing for classes and functions
|
|
@@ -130,11 +134,20 @@
|
|
|
|
def evalsource(self,text,line=0):
|
|
sc = self.parser.parse(text,line)
|
|
+ try: allow_imports = int(
|
|
+ vim.eval("get(g:, 'pythoncomplete_allow_import', 0)"))
|
|
+ except Exception:
|
|
+ allow_imports = 0
|
|
src = sc.get_code()
|
|
dbg("source: %s" % src)
|
|
try: exec(src,self.compldict)
|
|
except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1]))
|
|
for l in sc.locals:
|
|
+ # Executing import/from statements harvested from the buffer runs
|
|
+ # arbitrary package code; only do so when the user opted in.
|
|
+ if not allow_imports and (l.startswith('import')
|
|
+ or l.startswith('from ')):
|
|
+ continue
|
|
try: exec(l,self.compldict)
|
|
except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))
|
|
|
|
@@ -298,13 +311,11 @@
|
|
def get_code(self):
|
|
str = ""
|
|
if len(self.docstr) > 0: str += repr(self.docstr)+'\n'
|
|
- for l in self.locals:
|
|
- if l.startswith('import'): str += l+'\n'
|
|
str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n'
|
|
for sub in self.subscopes:
|
|
str += sub.get_code()
|
|
for l in self.locals:
|
|
- if not l.startswith('import'): str += l+'\n'
|
|
+ if not l.startswith('import') and not l.startswith('from '): str += l+'\n'
|
|
|
|
return str
|
|
|
|
diff --git a/runtime/autoload/pythoncomplete.vim b/runtime/autoload/pythoncomplete.vim
|
|
--- a/runtime/autoload/pythoncomplete.vim
|
|
+++ b/runtime/autoload/pythoncomplete.vim
|
|
@@ -12,6 +12,10 @@
|
|
" i.e. "import url<c-x,c-o>"
|
|
" Continue parsing on invalid line??
|
|
"
|
|
+" v 0.10 by Vim project
|
|
+" * disables importing local modules, unless the global Vim variable
|
|
+" g:pythoncomplete_allow_import is set to non-zero
|
|
+"
|
|
|
|
" v 0.9
|
|
" * Fixed docstring parsing for classes and functions
|
|
@@ -147,11 +151,20 @@
|
|
|
|
def evalsource(self,text,line=0):
|
|
sc = self.parser.parse(text,line)
|
|
+ try: allow_imports = int(
|
|
+ vim.eval("get(g:, 'pythoncomplete_allow_import', 0)"))
|
|
+ except Exception:
|
|
+ allow_imports = 0
|
|
src = sc.get_code()
|
|
dbg("source: %s" % src)
|
|
try: exec(src) in self.compldict
|
|
except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1]))
|
|
for l in sc.locals:
|
|
+ # Executing import/from statements harvested from the buffer runs
|
|
+ # arbitrary package code; only do so when the user opted in.
|
|
+ if not allow_imports and (l.startswith('import')
|
|
+ or l.startswith('from ')):
|
|
+ continue
|
|
try: exec(l) in self.compldict
|
|
except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))
|
|
|
|
@@ -316,13 +329,11 @@
|
|
def get_code(self):
|
|
str = ""
|
|
if len(self.docstr) > 0: str += repr(self.docstr)+'\n'
|
|
- for l in self.locals:
|
|
- if l.startswith('import'): str += l+'\n'
|
|
str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n'
|
|
for sub in self.subscopes:
|
|
str += sub.get_code()
|
|
for l in self.locals:
|
|
- if not l.startswith('import'): str += l+'\n'
|
|
+ if not l.startswith('import') and not l.startswith('from '): str += l+'\n'
|
|
|
|
return str
|
|
|
|
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
|
|
--- a/runtime/doc/filetype.txt
|
|
+++ b/runtime/doc/filetype.txt
|
|
@@ -658,7 +658,20 @@
|
|
To disable this behavior, set the following variable in your vimrc: >
|
|
|
|
let g:python_recommended_style = 0
|
|
+<
|
|
+Python omni-completion |compl-omni| is provided by python3complete.vim (or
|
|
+pythoncomplete.vim) for Vim builds with the |+python|/|+python3| interpreter.
|
|
+By default it does not inspect the import / from statements found in the
|
|
+buffer. This means completion of names defined in the buffer itself (classes,
|
|
+functions, variables) works, but completion of members of imported modules is
|
|
+not offered.
|
|
|
|
+To enable completion of imported module members, set: >
|
|
+ let g:pythoncomplete_allow_import = 1
|
|
+<
|
|
+WARNING: enabling this causes omni-completion to execute the import statements
|
|
+found in the buffer through Python's import machinery, which runs the imported
|
|
+modules' top-level code. Only enable this for code you trust.
|
|
|
|
QF QUICKFIX *qf.vim* *ft-qf-plugin*
|
|
|