Skip to content

GHSA-52mc-rq6p-rc7c

CVE Information

Arbitrary Code Execution via Python Omni-Completion in Vim < 9.2.561

Date: 29.05.2026 Severity: Medium CVE: CVE-2026-52858 CWE: Improper Control of Generation of Code (CWE-94), Inclusion of Functionality from Untrusted Control Sphere (CWE-829)

Summary

The Python omni-completion script in python3complete.vim for Vim with the +python3 interpreter enabled (and the legacy pythoncomplete.vim for builds with the +python interpreter) executes the import and from statements found in the current buffer through Python's import machinery. Because the buffer's working directory is on sys.path, opening a hostile .py file with a sibling Python package and invoking omni-completion runs that package's top-level code as the editing user.

Description

runtime/ftplugin/python.vim installs omnifunc=python3complete#Complete on every Python buffer when Vim has +python3 (or +python). When the user invokes omni-completion with CTRL-X CTRL-O in insert mode, the completer parses the buffer with an embedded Python tokenizer, regenerates a Python source string from the parsed scope, and passes it to exec(src, self.compldict) to populate the completion dictionary.

The regenerated source re-emits every top-level import X and from X import Y statement that the parser harvested from the buffer. Additionally, the completer extends sys.path with ['.', '..'] so that sibling modules in the buffer's working directory are importable. The combined effect: invoking omni-completion on a .py file runs Python's import machinery on attacker-supplied module names with the attacker's working directory on the search path.

A crafted .py file containing import evil_pkg and a sibling evil_pkg/__init__.py in the same directory will execute the __init__.py code when the victim opens the file and presses CTRL-X CTRL-O.

Impact

Arbitrary local code execution as the user running Vim, with the user's full credential set (SSH keys, cloud credentials, etc.), file-system access, and network egress. Realistic delivery vectors include:

  • reviewing a third-party Python contribution by checking out a fork branch and opening any .py file in it,
  • auditing an extracted source tarball, malware sample, or repository whose layout the attacker controls,
  • opening a .py file from any downloaded archive where the extracted layout places a hostile package next to the file being inspected.

Exploitation requires:

  • Vim built with +python3 (or +python3/dyn with a working Python 3 runtime)
  • Filetype plugins enabled (filetype plugin on, the default in runtime/defaults.vim and most distribution vimrcs).
  • The victim opens the hostile .py file from the attacker-controlled working directory and invokes omni-completion.

The severity is rated Medium because the user must manually invoke omni- completion after opening the file; the bug does not fire on file-open alone.

Mitigation

As of Vim patch v9.2.0561 the omni-completer no longer executes import or from statements harvested from the buffer by default. Users who require completion of imported module members (for example os.<C-X><C-O> offering getcwd, path, etc.) can opt back in with: >

let g:pythoncomplete_allow_import = 1

Setting this variable re-enables the import-execution behavior and should only be used when editing code from trusted sources. When the variable is unset or 0, in-buffer symbols (classes, functions, variables defined in the file) still complete normally; only completion of names that would require executing imports is unavailable.

Acknowledgements

The Vim project would like to thank github user tonghuaroot for reporting, analyzing the issue, providing a proof of concept and suggesting a fix.

References

The issue has been fixed as of Vim patch v9.2.0561. - Commit - Github Security Advisory