CVE-2026-52858
Description
Vim's Python omni-completion executes import statements from the buffer, allowing code execution via a crafted .py file; fixed in 9.2.0561.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Vim's Python omni-completion executes import statements from the buffer, allowing code execution via a crafted .py file; fixed in 9.2.0561.
Vulnerability
Vim versions prior to 9.2.0561 with the +python3 or +python interpreter enabled are vulnerable. The Python omni-completion scripts (python3complete.vim and pythoncomplete.vim) parse the current buffer and regenerate Python source code that includes import X and from X import Y statements. These are executed via Python's exec() function with the buffer's working directory on sys.path, allowing arbitrary package code to run. The vulnerability is triggered when a user opens a .py file and invokes omni-completion (CTRL-X CTRL-O) in insert mode [1][2].
Exploitation
An attacker crafts a .py file containing import evil_pkg and provides a sibling package evil_pkg/ with an __init__.py containing malicious code. When the victim opens the file in Vim and presses CTRL-X CTRL-O, the completer executes the import statement, loading and running the attacker's package code [2]. No special privileges are required beyond the ability to supply the malicious file to the victim.
Impact
Successful exploitation results in arbitrary code execution with the victim's privileges. The attacker gains access to the user's credentials, files, and network capabilities. Realistic delivery includes reviewing third-party code contributions or opening malicious files from untrusted sources [2].
Mitigation
Upgrade to Vim version 9.2.0561 or later, which disables the execution of import/from statements by default and introduces the g:pythoncomplete_allow_import option to opt in [1][3]. Users who cannot upgrade may set let g:pythoncomplete_allow_import = 0 in their vimrc to block the vulnerable behavior. The Vim project has patched the issue and released the fix [2][3].
AI Insight generated on Jun 11, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
14b850457e12epatch 9.2.0561: [security]: possible code execution with python3complete
5 files changed · +45 −7
runtime/autoload/python3complete.vim+14 −3 modified@@ -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 " * Fixed parsing of *args and **kwargs type arguments @@ -132,11 +136,20 @@ class Completer(object): 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)) @@ -300,13 +313,11 @@ class Scope(object): def get_code(self): str = "" if len(self.docstr) > 0: str += '"""'+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
runtime/autoload/pythoncomplete.vim+14 −3 modified@@ -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 " * Fixed parsing of *args and **kwargs type arguments @@ -146,11 +150,20 @@ class Completer(object): 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)) @@ -315,13 +328,11 @@ class Scope(object): def get_code(self): str = "" if len(self.docstr) > 0: str += '"""'+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
runtime/autoload/README.txt+1 −0 modified@@ -17,6 +17,7 @@ htmlcomplete.vim HTML 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)
runtime/doc/filetype.txt+14 −1 modified@@ -976,7 +976,20 @@ By default the following options are set, in accordance with PEP8: > 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*
src/version.c+2 −0 modified@@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 561, /**/ 560, /**/
Vulnerability mechanics
Root cause
"The Python omni-completion scripts re-emit and execute `import` and `from` statements from the buffer through Python's import machinery without user consent, allowing arbitrary package code to run."
Attack vector
An attacker crafts a malicious `.py` file containing `import evil_pkg` and places a sibling `evil_pkg/__init__.py` with arbitrary Python code in the same directory. When a victim opens the file in Vim (with `+python3` or `+python` enabled) and invokes omni-completion via `CTRL-X CTRL-O` in insert mode, the completer parses the buffer, regenerates the `import` statement, and executes it through Python's import machinery. Because the buffer's working directory is on `sys.path`, the attacker's package top-level code runs with the victim's privileges [ref_id=2].
Affected code
The vulnerability resides in `runtime/autoload/python3complete.vim` and `runtime/autoload/pythoncomplete.vim`. The `Completer.evalsource()` method and `Scope.get_code()` method both re-emit `import` and `from` statements harvested from the buffer, which are then passed to Python's `exec()` built-in. The patch also updates `runtime/doc/filetype.txt` to document the new opt-in variable `g:pythoncomplete_allow_import`.
What the fix does
The patch introduces a new global Vim variable `g:pythoncomplete_allow_import` that defaults to `0`. In `evalsource()`, the completer now checks this variable before executing any `import` or `from` statement harvested from the buffer; if the variable is falsy, those statements are skipped. Additionally, `get_code()` no longer includes `import` or `from` lines in the regenerated source string passed to `exec()`. This prevents untrusted import statements from being executed unless the user explicitly opts in [patch_id=5620674].
Preconditions
- configVim must be built with the +python3 or +python interpreter feature enabled
- inputThe user must open a .py file in a directory that contains a sibling Python package (e.g., a directory with an __init__.py)
- inputThe user must invoke omni-completion (CTRL-X CTRL-O) while editing the buffer
Generated on Jun 11, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
0No linked articles in our index yet.