-Infinity
0

Heap Buffer Overflow with Crafted Spell File in Vim < 9.2.1309 ============================================================== Date: 08.11.2026 Severity: Low CVE: requested, not yet assigned CWE: Access of Resource Using Incompatible Type (CWE-843), Out-of-bounds Read (CWE-125)

Summary A crafted spell file (.spl) containing two SNSOFO sections causes Vim to free the soundfolding items of the first section as if they were SNSAL items, reading beyond the allocated memory. The spell file can be loaded by a modeline, so opening a file is enough to trigger the issue.

Description The SNSAL and SNSOFO sections of a spell file both store their soundfolding information in slsal. For an SNSOFO section, setsofo() uses slsal as an array of 256 int pointers. Before doing so, it calls freesalitems() to free any previous contents, which treats the array as salitemT entries.

Vim only writes either an SNSAL or an SNSOFO section, but the spell file reader accepted any number of them. When a second SNSOFO section follows the first one, freesalitems() interprets the int array as salitemT entries, reading beyond the end of the allocation and passing the read values to vimfree().

Since 'spelllang' accepts the name of a .spl file and can be set from a modeline together with 'spell', a crafted spell file is loaded when a file containing such a modeline is opened.

Impact A heap out-of-bounds read, resulting in a crash of Vim. An invalid free has not been demonstrated but cannot be ruled out.

Exploitation requires:

the crafted .spl file and a file with a modeline setting 'spell' and 'spelllang' to it, e.g. in a cloned repository or an extracted archive, 'modeline' being enabled a multi-byte 'encoding' such as utf-8 (the default in most environments).

Acknowledgements The Vim project would like to thank pangflame for reporting the issue.

References The issue has been fixed as of Vim patch v9.2.1309.

- Commit - Github Security Advisory

Thanks, Christian -- Fenster verschmutzen viel weniger, wenn man die Scheiben herausnimmt.

Insecure Socket Directory in Vim < 9.2.1308 =========================================== Date: 08.11.2026 Severity: Medium CVE: requested, not yet assigned CWE: Unverified Ownership (CWE-283), Incorrect Default Permissions (CWE-276)

Summary When using the socketserver backend of the clientserver feature, Vim places its socket in a per-user directory such as /tmp/vim-<uid>. An existing directory was used without checking its owner or permissions, and the socket was created with the user's umask. A local attacker can pre-create this directory and then connect to or replace the victim's server socket, which allows evaluating arbitrary Vim expressions in the victim's Vim.

Description socketservergetpath() creates the socket directory $XDGRUNTIMEDIR/vim or $TMPDIR/vim-<uid> (/tmp if $TMPDIR is unset) using:

if (vimmkdir(buf, 0700) == -1 && errno != EEXIST) continue;

If the directory already exists, it is used as-is. Since /tmp is world-writable, another user can create /tmp/vim-<uid> for the victim's uid beforehand, owned by the attacker and with permissive mode. channellistenunix() then binds the server socket inside that directory with permissions 0777 & ~umask. The socketserver does not authenticate connecting clients and evaluates "expr" messages using evalclientexprtostring(), and "keystrokes" messages are inserted into the input buffer.

With a permissive umask (e.g. 002 or 000) the attacker can connect to the socket directly. With the common umask 022 a direct connect fails, but since the attacker owns the directory, they can still remove or replace the socket and impersonate the server towards clients.

Impact Arbitrary Vim expression evaluation, and therefore arbitrary shell command execution, in the context of the user running Vim, on multi-user systems.

Exploitation requires:

a Vim build with the +socketserver feature, used as server (e.g. using --servername or with +autoservername), the attacker having a local account on the same system, the socket directory being located in a shared directory such as /tmp ($XDGRUNTIMEDIR is not affected, since it is only accessible by the user), for direct code execution: a umask that makes the socket accessible by the attacker.

Acknowledgements The Vim project would like to thank Calif.io and 360AlphaLab for independently reporting the issue.

References The issue has been fixed as of Vim patch v9.2.1308.

- Commit - Github Security Advisory

Thanks, Christian -- Das Glück kann nicht wie ein mathematischer Lehrsatz bewiesen werden, es muß empfunden werden, wenn es da sein soll. -- Heinrich von Kleist

Ex Command Execution via Cargo Quickfix Hooks in Vim < 9.2.1201 =============================================================== Date: 15.10.2026 Severity: Medium CVE: requested, not yet assigned CWE: Improper Neutralization of Special Elements used in a Command (CWE-77), Improper Neutralization of Special Elements used in an OS Command (CWE-78)

Summary The Rust support in runtime/autoload/cargo/quickfix.vim changes to the directory of the nearest Cargo.toml before running :make and restores the previous directory afterwards. The directory names were passed unescaped to the :lchdir and :chdir Ex commands, so a crafted directory name can inject arbitrary Ex commands, including running shell commands, when the user runs :make in a Rust buffer.

Description When the cargo compiler is active for a Rust buffer, the QuickFixCmdPre and QuickFixCmdPost autocommands call cargo#quickfix#CmdPre() and cargo#quickfix#CmdPost(). CmdPre() determines the directory of the nearest Cargo.toml and changes into it using:

execute 'lchdir! ' . l:nearest

The directory name is not escaped. Since :lchdir treats | as a command separator, a directory name such as x|call system('...') containing a Cargo.toml file causes the text after the | to be executed as an Ex command. CmdPost() restores the previous directory in the same unescaped way.

Impact Arbitrary Ex command execution, and therefore arbitrary shell command execution, in the context of the user running Vim, when the user runs :make on a Rust file inside a crafted directory tree, e.g. a cloned repository.

Exploitation requires:

a system that allows to use "|" in a directory name a Rust buffer using the cargo compiler, the victim running :make within a crafted directory tree.

Acknowledgements The Vim project would like to thank github user @Dalvelac for reporting the issue.

References The issue has been fixed as of Vim patch v9.2.1201.

- Commit - Github Security Advisory

Best, Christian -- Ist erst die letzte Klammer zu, hat der Lispler seine Ruh.

Command Execution via Rmd Syntax Highlighting in Vim < 9.2.1178 =============================================================== Date: 12.10.2026 Severity: Medium CVE: requested, not yet assigned CWE: Improper Neutralization of Special Elements used in an OS Command (CWE-78), Improper Input Validation (CWE-20)

Summary The R Markdown syntax script in runtime/syntax/rmd.vim collects the language names of code chunks from the buffer and passes them to globpath(). The script strips non-word characters from each name with a regular expression, which a crafted byte sequence can make stop early, so text from the file reaches globpath() unfiltered. On Unix, globpath() hands such a pattern to the shell, which allows arbitrary command execution when the file is opened.

Description With the default g:rmddynamicfencedlanguages, s:CheckRmdFencedLanguages() reads the language name of every code chunk in the buffer and calls s:IncludeLanguage() for names it has not seen yet, which checks for a matching syntax file using globpath().

The name was trimmed with substitute(v:val, '\W.', '', ''). The NFA regexp engine treats an overlong UTF-8 encoding of NUL as the end of the text, so the pattern does not match and the rest of the name is kept. If the name contains backticks, globpath() passes it to the shell for expansion.

Impact Arbitrary command execution in the context of the user running Vim, when the user opens a crafted R Markdown or Quarto file (.rmd, .smd, .qmd and similar).

Exploitation requires: - a Unix-like system (on Windows globpath() does not invoke the shell), - syntax highlighting enabled - the victim opening a crafted file.

The severity is rated Medium because the user must open a crafted file of a specific rmd file type.

Acknowledgements The Vim project would like to thank github user tylerni7-ant for reporting and analyzing the issue.

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

Thanks, Christian -- Wo man arbeitet, da ist genug; wo man aber mit Worten umgeht, da ist Mangel. -- Salomo

Arbitrary Code Execution via Ruby Omni-Completion in Vim < 9.2.1177 =================================================================== Date: 12.10.2026 Severity: Medium CVE: requested, not yet assigned CWE: Improper Neutralization of Directives in Dynamically Evaluated Code (CWE-95), Improper Control of Generation of Code (CWE-94)

Summary The Ruby omni-completion script in runtime/autoload/rubycomplete.vim derives the type of a variable from the contents of the edited buffer and passes that text to Ruby's eval() without checking that it is a class name. A crafted Ruby file can place a Ruby expression where a class name is expected, which is evaluated when the user invokes omni-completion.

Description runtime/ftplugin/ruby.vim installs omnifunc=rubycomplete#Complete on every Ruby buffer when Vim is built with the Ruby interface. When completing after a variable reference, s:GetRubyVarType() takes the variable's type from its assignment in the buffer, and the result is passed to eval().

:help ft-ruby-omni states that evaluating buffer code for completion must be opted into with g:rubycompletebufferloading. This code path is not covered by that setting and is reachable in the default configuration.

Impact Arbitrary Ruby code execution, and therefore arbitrary operating-system command execution, in the context of the user running Vim.

Exploitation requires:

- Vim built with the Ruby interface (+ruby or +ruby/dyn), - filetype plugins enabled - the victim opening a crafted Ruby file and invoking omni-completion.

The severity is rated Medium because the user must open a crafted file and invoke omni-completion. The bug does not fire on file-open alone.

Acknowledgements The Vim project would like to thank github user @tnshima for reporting and analyzing the issue.

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

Thanks, Christian -- Wer die Wahrheit geigt, dem schlägt man leicht die Fiedel auf den Kopf. -- Jean Paul (eig. Johann Paul Friedrich Richter)

Ex Command Injection via Unescaped Buffer Name in signjump() in Vim < v9.2.1090 ================================================================================

Date: 12.09.2026 Severity: Low CVE: requested, not yet assigned CWE: Improper Neutralization of Argument Delimiters in a Command ('Argument Injection') (CWE-88), Improper Control of Generation of Code ('Code Injection') (CWE-94)

Summary

When jumping to a sign in a buffer that is not displayed in any window, Vim re-opens that buffer by building an Ex command line from the buffer's file name and executing it. The file name is interpolated without escaping, so a name containing the Ex command separator | is split into two commands, the second of which is taken from the file name.

Description

signjump() in src/sign.c handles the case where the buffer holding the sign is not shown in any window: c charu cmd = alloc(STRLEN(buf->bfname) + 25); if (cmd == NULL) return -1;

sprintf((char )cmd, "e +%ld %s", (long)lnum, buf->bfname); docmdlinecmd(cmd); buf->bfname is stored as given and is not escaped via fnameescape(). Unix permits | in a file name, and docmdlinecmd() treats it as a command separator, so a buffer named pwn|:silent !cmd results in two Ex commands being executed: the :edit, which fails, and whatever follows the bar.

The branch is reached only when the buffer is not displayed in any window, that is when bufjumpopenwin() returns NULL. It is used by the :sign jump command and by the signjump() function.

The issue has been addressed by opening the buffer by its number with doecmd() instead of synthesizing a command line, so that no escaping is required.

Impact

Arbitrary Ex command execution, and through commands such as :! arbitrary operating system command execution, in the context of the user running Vim. Vim must be built with +signs, which is the default in normal builds.

The severity is rated Low. Execution requires a buffer whose name contains | or a newline, a sign placed in that buffer, the buffer not being shown in any window, and :sign jump or signjump() being invoked on it. These are deliberate steps by the user rather than a consequence of opening a file, and the commands run with no privilege beyond the user's own account.

Acknowledgements

The Vim project would like to thank Ahmed Ibrahim (@skeletonsec) for reporting the issue.

References

The issue has been fixed as of Vim patch v9.2.1090.

- Commit - Github Security Advisory

Best, Christian -- Sperma light = Macht schwanger, aber nicht dick!

Integer Overflow in Undo File Entry Size Check in Vim < v9.2.1014 && Vim >= v8.1.0688 =====================================================================================

Date: 26.08.2026 Severity: Low CVE: requested, not yet assigned CWE: Integer Overflow or Wraparound (CWE-190), Out-of-bounds Write (CWE-787)

Summary

When Vim reads a persistent undo file it allocates an array holding the lines of an undo entry, with the number of lines taken from the file. The check that guards this allocation against an overflow of the multiplication compares against the size of a pointer, while the array is allocated using the size of its actual element type, which is three times larger on a 32-bit system. The check therefore accepts a line count for which the multiplication does not fit, resulting in an allocation that is much smaller than requested.

Only 32-bit builds of Vim are affected.

Description

unserializeuep() in src/undo.c reads the number of lines of an undo entry from the file and allocates the array for them:

if (uep->uesize < LONGMAX / (int)sizeof(charu )) array = UALLOCLINE(sizeof(undolineT) uep->uesize);

The multiplication is computed with type sizet, which wraps around instead of failing when the result does not fit. The check exists to prevent that, but it uses the size of a pointer where the allocation uses the size of undolineT. On a 32-bit system a pointer is 4 bytes and undolineT is 12, so the check permits a line count three times larger than the one at which the multiplication starts to wrap.

For a line count in that range the allocation succeeds with a size much smaller than needed, and the loop that follows fills the array using the line count from the file, writing past the end of the allocation.

Until patch v8.1.0688 the array held plain pointers and the check was correct. That patch changed the element type to undolineT so that text properties are restored by undo, and updated the allocation but not the check.

On 64-bit builds the line count is read as a 32-bit value and the multiplication cannot overflow a 64-bit sizet, so those builds are not affected.

The issue has been addressed by using the size of undolineT for the check as well.

Impact

Heap out-of-bounds write in the process running Vim, when a crafted undo file is read. This happens either explicitly with :rundo, or automatically when 'undofile' is set and Vim finds a matching undo file for the edited file.

The values written are a heap pointer and two lengths derived from the undo file rather than freely chosen data, and the write proceeds sequentially from the end of the allocation, so the expected consequence is heap corruption leading to a crash.

The severity is rated Low. Besides being limited to 32-bit builds, a crafted file must contain a valid entry for every line up to the point where the allocation ends, which for the smallest overflowing line count means an undo file of well over a hundred megabytes. Whether the wrapped allocation succeeds at all depends on the memory available to a 32-bit process.

Acknowledgements

The Vim project would like to thank Yazan Balawneh, Cystack.ps for reporting the issue.

References

The issue has been fixed as of Vim patch v9.2.1014.

- Commit - Github Security Advisory

Best, Christian -- Bienen sind gar nicht so fleißig, sie können nur nicht langsam fliegen.

Out-of-bounds Access in libvterm Resize Handling in Vim < 9.2.1013 ==================================================================

Date: 26.08.2026 Severity: Medium CVE: requested, not yet assigned CWE: Out-of-bounds Write (CWE-787), Improper Validation of Specified Quantity in Input (CWE-1284)

Summary

The bundled libvterm keeps the terminal size in two places: VTermState, which holds the cursor position and the bounds used to clamp it, and VTermScreen, which owns the storage for the cells and the line information. The CSI 8 ; rows ; cols t sequence, with which a program running in a terminal window asks for a new size, was written into VTermState unchanged, while the screen clamped it to VTERMMAXROWS and VTERMMAXCOLS when allocating the storage. The clamped value was not reported back, so the state kept the requested size. All later bound checks then used a size that is much larger than the allocated line information, and ordinary text output could move the cursor beyond it, reading and writing past the end of the allocation.

Description

Programs in a terminal window can send CSI 8 ; rows ; cols t to request a new size. The only limit on the values is the one the argument parser applies to any numeric argument, about 1.07 billion. onresize() in src/libvterm/src/state.c stored them directly:

state->rows = rows; state->cols = cols;

and raised scrollregionbottom accordingly, before calling the resize callback. That callback, resize() in src/libvterm/src/screen.c, clamps the size to VTERMMAXROWS and VTERMMAXCOLS, both 1000, and allocates the VTermLineInfo array for the clamped number of rows. It updates the screen's own size but has no way to correct the state, and onresize() does not read the size back.

After a request such as CSI 8 ; 50000 ; 200 t the state therefore reports 50000 rows while the line information holds 1000 entries. Because the scroll region was widened as well, linefeed() no longer scrolls at the bottom of the screen, it only advances the cursor row. Printing more than 1000 lines, or printing enough text to wrap that often, moves the cursor past the end of the array.

The issue has been addressed by clamping the requested size to the same limits the screen uses, at the start of onresize(), before the state is updated and before any storage is allocated.

Impact

Heap out-of-bounds read and write in the process running Vim. The values written are small fixed constants rather than attacker-controlled data and the offset follows the amount of output produced, so the demonstrated consequence is memory corruption leading to a crash. There is no channel through which the program in the terminal can observe what is read.

Exploitation requires:

- Vim compiled with the terminal feature and a terminal window open, - output rendered in that window from a program under the attacker's control, for example a connection to a malicious SSH server, a file shown with a pager, or the log of a compromised build tool, - the escape sequence and the following output to arrive together, without Vim redrawing in between, which happens for any program producing a continuous stream of output.

No privileges on the host running Vim are needed and the sequence is ordinary output on the program's own standard output stream. The severity is rated Medium because the impact demonstrated is a denial of service rather than control over the process, and because the attacker must already have output displayed in a terminal window.

This is the second issue in the same sequence in the bundled libvterm. Patch v9.2.0569 rejected missing, zero and negative dimensions, however the values above the supported maximum remained unchecked.

Acknowledgements

The Vim project would like to thank Yazan Balawneh, Cystack.ps for reporting the issue.

References

The issue has been fixed as of Vim patch v9.2.1013.

- Commit - Github Security Advisory - Related patch v9.2.0569

Best, Christian -- Wer selbst keine Handlungskompetenzen hat, kann nicht wissen, wie man diese am besten vermittelt bekommt. -- Nils Krüger

Arbitrary Ex Command Execution via File Names in C Omni-Completion in Vim < 9.2.1011 ====================================================================================

Date: 25.08.2026 Severity: Medium CVE: requested, not yet assigned CWE: Improper Control of Generation of Code ('Code Injection') (CWE-94), Inclusion of Functionality from Untrusted Control Sphere (CWE-829), Improper Neutralization of Argument Delimiters in a Command ('Argument Injection') (CWE-88)

Summary

The C omni-completion script in runtime/autoload/ccomplete.vim looks up struct members by building a :vimgrep command and running it with :execute. Besides the type name, that command line also holds the list of tags file names returned by tagfiles(). Those names were escaped for the space, the backslash, # and %, but not for the bar. Since :vimgrep accepts another command after a bar, a file name whose name contains one ends the :vimgrep command early and what follows is executed as an Ex command when the user invokes omni-completion on a member access.

This is the same defect in the same command line as GHSA-cx73-phcg-3j5g, fixed in patch v9.2.0845, which addressed only the type name. Unlike that issue, no crafted tags file content is needed here: the file name itself carries the payload.

Description

runtime/ftplugin/c.vim sets omnifunc=ccomplete#Complete on C buffers when filetype plugins are enabled. When completing a member access, and the declaration is not found in the buffer itself, StructMembers() searches the tags files:

var fnames: string = tagfiles() ->map((, v: string) => escape(v, ' \#%')) ->join() ... execute 'silent! keepjumps noautocmd ' .. n .. 'vimgrep ' .. '/\t\V' .. escape(typename, '/\') .. '\m\(\t\|$\)/j ' .. fnames

tagfiles() returns the names of the tags files in effect for the buffer, derived from the 'tags' option. The names are appended unquoted to the :vimgrep argument list.

The :vimgrep command is defined with the EXTRLBAR flag, so a bar ends the command and starts a new one. A bar in a file name is therefore not part of the name but a command separator, and the remainder of the line is parsed and executed as an independent Ex command by the same :execute. Escaping the space limits what such a command can contain, but does not prevent it, and ccomplete.vim is a vim9script file, so the injected text is parsed with Vim9 syntax. The leading :silent! suppresses the resulting error, so the injected command runs without a visible failure.

The issue has been addressed by escaping the bar in the tags file names as well.

Impact

Arbitrary Ex command execution, and through commands such as :! arbitrary operating-system command execution, in the context of the user running Vim. Exploitation requires:

- Vim with filetype plugins enabled - a tags file whose path contains a bar, for example because it is stored in a directory whose name contains one, and a 'tags' value under which that file is found, - the victim opening a C file from that tree and invoking omni-completion with CTRL-X CTRL-O on a member access whose type is only known from the tags file.

The severity is rated Medium. The payload travels in a path rather than in file content, so it is not visible to review that inspects files only. On the other hand a bar in a directory name is unusual and conspicuous, it is not a valid character in file names on MS-Windows, and the crafted name has no effect until the user deliberately invokes omni-completion on a type that is not declared in the edited buffer, since the completion would otherwise not consult the tags files at all.

Acknowledgements

The Vim project would like to thank Yazan Balawneh, Cystack.ps for reporting the issue.

References

The issue has been fixed as of Vim patch v9.2.1011.

- Commit - Github Security Advisory

Best, Christian -- Auge um Auge - und die ganze Welt wird blind sein. -- Mahatma Gandhi

Severity
7.8
Code Injection
AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

A flaw was found in Vim's netrw plugin. A crafted filename containing quote characters and expression fragments can break out of the quoted context during mark/unmark operations, allowing arbitrary Vimscript execution. This can be leveraged to run shell commands with the privileges of the user running Vim.

First published (updated )
Severity
7

Vim is an open source, command line text editor. Prior to 9.2.0845, StructMembers() in runtime/autoload/ccomplete.vim constructs and executes a vimgrep command using an insufficiently escaped typeref: or typename: value from a tags file, allowing an unterminated collection followed by a command separator to execute arbitrary Ex and operating-system commands when a user invokes C omni-completion with CTRL-X CTRL-O on a member access whose type is resolved from that tags file. This issue is fixed in version 9.2.0845.

First published (updated )
Severity
7.1
Code Injection
AV:L/AC:L/AT:P/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Last updated 9 September 2026

1 / 3
Source: Ubuntu
First published (updated )
Severity
7

Vim is an open source, command line text editor. Prior to 9.2.0839, the runtime/ftplugin/sh.vim, runtime/ftplugin/zsh.vim, and runtime/ftplugin/ps1.vim filetype plugins pass attacker-controlled Visual-mode selections from K through keywordprg commands without safely separating shell arguments. fnameescape() and PATHESCCHARS do not neutralize shell metacharacters before ShKeywordPrg, ZshKeywordPrg, or GetHelp invokes bash, zsh, or PowerShell, allowing arbitrary operating-system commands to execute with the privileges of the user running Vim. This issue is fixed in version 9.2.0839.

First published (updated )
Severity
7

Vim is an open source, command line text editor. Prior to 9.2.0840, runtime/plugin/netrwPlugin.vim loads netrw and runtime/pack/dist/opt/netrw/autoload/netrw.vim constructs Bookmarks, History, and Targets menu entries by interpolating attacker-controlled directory paths into executed :menu commands. s:NetrwBookmarkMenu(), s:NetrwTgtMenu(), g:netrwmenuescape, EXTRLBAR, and netrw#MakeTgt() fail to neutralize the | command separator or single quotes at five construction sites, allowing a crafted path browsed or bookmarked in GUI Vim to execute arbitrary Ex and operating-system commands. This issue is fixed in version 9.2.0840.

First published (updated )
Severity
8.6
Command Injection
AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Vim is an open source, command line text editor. Prior to 9.2.0840, runtime/plugin/netrwPlugin.vim loads netrw and runtime/pack/dist/opt/netrw/autoload/netrw.vim constructs Bookmarks, History, and Targets menu entries by interpolating attacker-controlled directory paths into executed :menu commands. s:NetrwBookmarkMenu(), s:NetrwTgtMenu(), g:netrwmenuescape, EXTRLBAR, and netrw#MakeTgt() fail to neutralize the | command separator or single quotes at five construction sites, allowing a crafted path browsed or bookmarked in GUI Vim to execute arbitrary Ex and operating-system commands. This issue is fixed in version 9.2.0840.

1 / 2
Source: NVD
First published (updated )
Severity
7

Vim is an open source, command line text editor. Prior to 9.2.0846, setsofo() in src/spellfile.c reuses slsalfirst[] without resetting values left by setsalfirst(), so a crafted spell file containing an SNSAL section before an SNSOFO section causes under-counted mapping lists and attacker-influenced writes beyond a heap allocation. This issue is fixed in version 9.2.0846.

First published (updated )
Severity
7

Vim is an open source, command line text editor. Prior to 9.2.0847, runtime/autoload/vimball.vim allows a crafted vimball member named .VimballRecord to overwrite the installation record with attacker-chosen commands. When vimball#RmVimball() later processes the matching record entry, the stored Ex commands, including operating-system commands invoked through :!, execute with the privileges of the user running Vim. This issue is fixed in version 9.2.0847.

First published (updated )
Severity
8.4
OS Command Injection
AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Vim is an open source, command line text editor. Prior to 9.2.0839, the runtime/ftplugin/sh.vim, runtime/ftplugin/zsh.vim, and runtime/ftplugin/ps1.vim filetype plugins pass attacker-controlled Visual-mode selections from K through keywordprg commands without safely separating shell arguments. fnameescape() and PATHESCCHARS do not neutralize shell metacharacters before ShKeywordPrg, ZshKeywordPrg, or GetHelp invokes bash, zsh, or PowerShell, allowing arbitrary operating-system commands to execute with the privileges of the user running Vim. This issue is fixed in version 9.2.0839.

1 / 2
Source: NVD
First published (updated )
Severity
8.4
Code Injection
AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Vim is an open source, command line text editor. Prior to 9.2.0847, runtime/autoload/vimball.vim allows a crafted vimball member named .VimballRecord to overwrite the installation record with attacker-chosen commands. When vimball#RmVimball() later processes the matching record entry, the stored Ex commands, including operating-system commands invoked through :!, execute with the privileges of the user running Vim. This issue is fixed in version 9.2.0847.

1 / 2
Source: NVD
First published (updated )
Severity
4.6
AV:L/AC:L/AT:N/PR:N/UI:A/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Vim is an open source, command line text editor. From 9.2.0469 until 9.2.0843, popupmarkopacityzindex() in src/popupwin.c can use a negative wwinrow for a text-property-anchored popup with clipwindow and opacity, indexing before the screen array instead of accounting for wpopuptopoff and causing an out-of-bounds read and conditional write. This issue is fixed in version 9.2.0843.

1 / 2
Source: NVD
First published (updated )
Severity
7.1
Integer Overflow, Buffer Overflow
AV:L/AC:H/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Vim is an open source, command line text editor. Prior to 9.2.0841, propaddone() in src/textprop.c uses the proplen value from gettextprops() to increment a uint16t property count beyond 0xffff, wrapping the count to zero and copying existing text-property records into a heap allocation sized for none of them. This issue is fixed in version 9.2.0841.

1 / 2
Source: NVD
First published (updated )
Severity
7.1
Integer Overflow
AV:L/AC:H/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Vim is an open source, command line text editor. Prior to 9.2.0841, propaddone() in src/textprop.c uses the proplen value from gettextprops() to increment a uint16t property count beyond 0xffff, wrapping the count to zero and copying existing text-property records into a heap allocation sized for none of them. This issue is fixed in version 9.2.0841.

First published (updated )
Severity
8.5
Buffer Overflow
AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Vim is an open source, command line text editor. Prior to 9.2.0846, setsofo() in src/spellfile.c reuses slsalfirst[] without resetting values left by setsalfirst(), so a crafted spell file containing an SNSAL section before an SNSOFO section causes under-counted mapping lists and attacker-influenced writes beyond a heap allocation. This issue is fixed in version 9.2.0846.

1 / 2
Source: MITRE
First published (updated )
Severity
3.3
Use After Free
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L

Vim is an open source, command line text editor. From 9.2.0511 until 9.2.0844, jsondecodeitem() in src/json.c can retain a stale pointer after jsondecodestring() invokes channelfill() to refill and free the current buffer, causing the error path to read freed memory instead of reader->jsbuf + reader->jsused when an invalid JSON string spans buffers. This issue is fixed in version 9.2.0844.

1 / 2
Source: NVD
First published (updated )
Severity
6.8
Buffer Overflow
AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Vim is an open source, command line text editor. Prior to 9.2.0842, the socket server backend in src/socketserver.c accepts unbounded client connections in socketserveraccept(), causing descriptors to overflow fdset structures in src/channel.c and fixed-size struct pollfd arrays in src/osunix.c, which allows a local process that can connect to the server socket to corrupt stack memory or terminate the Vim server. This issue is fixed in version 9.2.0842.

1 / 2
Source: NVD
First published (updated )
Severity
8.4
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

An issue in Vim Project v9.2.0389 and earlier allows a local attacker to execute arbitrary code via the vmsfixfilename() function within file vim/src/osvms.c

First published (updated )
Severity
7.7
Code Injection
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

An issue in Vim Project v9.2.0389 and earlier allows a local attacker to execute arbitrary code via the vmsfixfilename() function within file vim/src/osvms.c

First published (updated )

Arbitrary Command Execution via the Vimball Record File in Vim < 9.2.0847 =========================================================================

Date: 24.07.2026 Severity: Medium CVE: requested, not yet assigned CWE: Improper Control of Generation of Code (CWE-94), Inclusion of Functionality from Untrusted Control Sphere (CWE-829)

Summary

The vimball plugin records the files it extracts in a plain text file named .VimballRecord, so that they can be removed again later. Each line of that file holds the commands to undo one installation, and they were executed without being checked. The plugin refused to extract members whose name could inject into that file, but it did not refuse a member that is the record file. A crafted vimball can therefore write chosen commands into the record, which are then executed the next time any vimball operation consults it.

Description

runtime/autoload/vimball.vim writes one line per installed vimball into .VimballRecord in the directory used for vimball installations, listing the commands that delete the files that were extracted. When a vimball is installed or removed, vimball#RmVimball() searches that file for the line belonging to the archive, strips the archive name from the front of it and runs the remainder:

sil! keepalt keepjumps exe exestring

The name of each member of an archive was already checked, and names that contain a bar, a quote or a closing parenthesis were rejected, precisely so that a file name could not inject commands into the record. That check does not apply to a member whose name is .VimballRecord itself: extracting it overwrites the record with content taken straight from the archive, and the content of a member is not examined at all.

The commands placed there are run later, when a vimball with the matching name is installed or removed, and not while the crafted archive is being extracted.

The issue has been addressed by refusing to extract a member named .VimballRecord, and by executing only entries of the expected form, namely a single call that deletes one file or directory. Anything else in the record is reported and skipped.

Impact

Execution of arbitrary Ex commands, and through commands such as :! arbitrary operating-system commands, in the context of the user running Vim.

Exploitation requires the victim to install a vimball from a source controlled by the attacker, either by sourcing it or through the getscript plugin, which downloads and sources vimballs automatically. Installing a vimball already runs the commands contained in it, so the attacker does not gain the ability to run commands as such. What the issue adds is that the archive itself can appear harmless while leaving commands behind that run at a later time, during an unrelated vimball installation or removal, and that continue to do so after the archive that placed them has been removed.

The severity is rated Medium because installing a vimball from an untrusted source already permits commands from that vimball to run, so the issue extends the reach of such an installation rather than creating it.

Acknowledgements

The Vim project would like to thank tdjackey for reporting the issue.

References

The issue has been fixed as of Vim patch v9.2.0847.

- Commit - Github Security Advisory

Best, Chris -- Man sagt nicht 'Nichts!', man sagt dafür 'Jenseits' oder 'Gott'. -- Friedrich Wilhelm Nietzsche

Heap Buffer Overflow when Loading a Spell File in Vim < 9.2.0846 ================================================================

Date: 24.07.2026 Severity: Medium CVE: requested, not yet assigned CWE: Heap-based Buffer Overflow (CWE-122), Out-of-bounds Write (CWE-787)

Summary

A spell file may contain a section holding sound-folding rules and a section holding a simple character mapping used for the same purpose. Reading the first of these fills an index table with the value minus one for every entry. Reading the second uses that same table to count how many mappings share a byte, but did not reset it beforehand, so every count came out one too low. The buffer allocated from that count is then too small for the mappings that are stored into it, and the surplus is written past its end. A crafted spell file therefore causes an out-of-bounds write when it is loaded, with part of the written data taken from the file.

Description

Vim loads a spell file when a language is selected with the 'spelllang' option. The file is a sequence of sections, and the loader in src/spellfile.c dispatches on the section identifier without imposing an order on them or requiring them to be unique.

Reading the sound-folding section ends with a call to setsalfirst(), which sets all 256 entries of the language's first-index table to minus one. This happens even when that section contains no rules at all.

Reading the character mapping section calls setsofo(), which reuses the same table as a temporary counter. For every mapped character above 255 it increments the entry belonging to the low byte of that character, allocates one list per entry from the resulting counts, and only afterwards clears the table again. Since the counting started from minus one rather than zero, each count is one too low. For a byte value used by two mapped characters the list is allocated for one pair and two are written into it, so the storing loop writes past the end of the allocation; part of what is written is the mapped-to character taken from the file. For a byte value used by exactly one mapped character the count becomes zero, no list is allocated at all, and the storing loop follows a null pointer.

The two sections are mutually exclusive by construction and the tool that generates spell files never emits both, but nothing in the loader rejected a file that contains them in that order.

The issue has been addressed by clearing the table before it is used as a counter.

Impact

An out-of-bounds write to the heap, or a null pointer dereference, while a spell file is being loaded. Part of the written data is taken from the spell file, and the sizes of the other sections in the same file influence the surrounding heap layout, so the effect is not limited to a crash, although no further consequence has been demonstrated.

Exploitation requires the victim to load a crafted spell file, which happens when 'spelllang' is set to a value naming that file, or to a language for which the crafted file is found in the directories searched for spell files. Vim must be built with the spell checking and multi-byte features, which is the case for the "huge" feature set used by most distributions.

The severity is rated Medium because a spell file has to be placed where Vim will load it and the option has to be set to select it.

Acknowledgements

The Vim project would like to thank Yazan Balawneh for reporting the issue.

References

The issue has been fixed as of Vim patch v9.2.0846.

- Commit - Github Security Advisory

Best, Chris -- "Friede seiner Asche" wird geschüttelreimt zu "Ade seiner Frische", was auf das gleiche hinauskommt.

Arbitrary Ex Command Execution in C Omni-Completion in Vim < 9.2.0845 ======================================================================

Date: 23.07.2026 Severity: Medium CVE: requested, not yet assigned CWE: Improper Control of Generation of Code ('Code Injection') (CWE-94), Inclusion of Functionality from Untrusted Control Sphere (CWE-829)

Summary

The C omni-completion script in runtime/autoload/ccomplete.vim looks up struct members by building a :vimgrep command that contains the type name taken from the typeref: field of a tags file entry, and running it with :execute. The value was escaped only for the pattern delimiter and the backslash. That is not sufficient: a value containing an unterminated collection makes Vim's own pattern skipping fail, after which the command parser looks for a command separator across the whole argument. A crafted tags file can therefore run arbitrary Ex commands, and through them shell commands, when the user invokes omni-completion on a member access.

This is a bypass of the fix released as patch v9.2.0735 for GHSA-mf92-v4xw-j45x, which prevented the same injection only for values containing the pattern delimiter.

Description

runtime/ftplugin/c.vim sets omnifunc=ccomplete#Complete on C buffers when filetype plugins are enabled. When completing a member access, and the declaration is not found in the buffer itself, StructMembers() searches the files listed in the tags file:

execute 'silent! keepjumps noautocmd ' .. n .. 'vimgrep ' .. '/\t' .. escape(typename, '/\') .. '\(\t\|$\)/j ' .. fnames

typename comes verbatim from the typeref: or typename: extension field of a tags entry, which Vim returns unchanged.

The :vimgrep command may be followed by another command after a bar, so before looking for that bar Vim first skips over the search pattern. When skipping the pattern does not end at the closing delimiter, the routine returns a failure and the caller silently falls back to the beginning of the argument, after which the first unescaped bar is treated as a command separator.

Skipping the pattern fails on an unterminated collection: an opening bracket makes the pattern skipping look for the matching closing bracket and run to the end of the text instead. A typeref: value that opens a bracket and then contains a bar therefore ends the :vimgrep command early, and what follows the bar is executed as an Ex command. No delimiter character is needed, so the escaping applied by the earlier fix does not prevent it. The leading :silent! suppresses the resulting error, so the injected command runs without a visible failure.

The issue has been addressed by matching the field literally, using the "very nomagic" mode for the part of the pattern that holds the value, so that no character in it can affect how the pattern is parsed.

Impact

Arbitrary Ex command execution, and through commands such as :! arbitrary operating-system command execution, in the context of the user running Vim. Exploitation requires:

- Vim with filetype plugins enabled, which is the default in runtime/defaults.vim and in most distribution configurations, so that the C omni-completion function is installed on C buffers, - a tags file under the attacker's control, which is ordinary data to receive together with source code, for example in a cloned repository or an unpacked archive, - the victim opening a C file from that tree and invoking omni-completion with CTRL-X CTRL-O on a member access whose type is only known from the tags file.

The severity is rated Medium because the crafted tags file has no effect until the user invokes omni-completion, which is a deliberate action, and because the type must not be declared in the edited buffer, since the completion would otherwise not consult the tags file at all.

Acknowledgements

The Vim project would like to thank Threonine for reporting the issue.

References

The issue has been fixed as of Vim patch v9.2.0845.

- Commit - Github Security Advisory

Best, Chris -- Verurteile niemanden, bevor du nicht in seiner Lage warst. -- Talmud (Literaturwerk des Judentums)

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203