﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	severity	resolution	keywords	cc
5982	vim-9.2.0843 (Security Update)	Joe Locash	lfs-book	"5 CVE's have been fixed.

{{{
Arbitrary Code Execution via Shell Keyword Lookup in Vim < 9.2.0839
===================================================================

Date: 23.07.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Improper Neutralization of Special Elements used in an OS Command
     (CWE-78)

## Summary

The shell filetype plugins `runtime/ftplugin/sh.vim` and
`runtime/ftplugin/zsh.vim` install a buffer-local `keywordprg` that
interpolates its argument into a `bash -c` or `zsh -c` command without
shell escaping.  Because a `keywordprg` beginning with `:` is escaped with
`fnameescape()`, which does not neutralize shell metacharacters, and because
`K` in Visual mode passes the whole selection verbatim, a crafted line in a
shell script can execute arbitrary commands when the user selects it and
presses `K`.  `runtime/ftplugin/ps1.vim` is affected in the same way through
PowerShell.

## Description

When a buffer's filetype resolves to bash, zsh or PowerShell, the bundled
filetype plugin defines a keyword lookup command and points `keywordprg` at
it, for example:

    command! -buffer -nargs=1 ShKeywordPrg silent exe
      \ ':hor term bash -c ""help ""<args>"" 2>/dev/null || man ""<args>""""'
    setlocal keywordprg=:ShKeywordPrg

For a `keywordprg` that starts with `:`, Vim escapes the argument of `K`
with `vim_strsave_fnameescape()` (`src/normal.c`), which uses
`PATH_ESC_CHARS` (`src/vim.h`).  That set omits the shell metacharacters
`;`, `&`, `(`, `)` and `>`; those appear only in `SHELL_ESC_CHARS`, which is
used exclusively for a `keywordprg` that is not an Ex command.  The filetype
plugin adds no escaping of its own, so these characters reach the inner
`bash -c` unchanged and terminate the intended command.

In Visual mode, `K` passes the entire selection rather than the keyword
under the cursor, so shell metacharacters are preserved.  In Normal mode the
argument is restricted to 'iskeyword' characters, which excludes these
metacharacters, and the issue does not arise.

The same pattern applies to `runtime/ftplugin/zsh.vim`, which builds a
`zsh -c` command, and to `runtime/ftplugin/ps1.vim`, which passes the
argument to PowerShell via `-Command`.

## Impact

Arbitrary operating-system command execution in the context of the user
running Vim.  Exploitation requires:

- Vim with filetype plugins enabled
- the buffer's filetype resolving to sh, bash, zsh or PowerShell
- the victim opening a crafted file, selecting the crafted line in Visual
  mode and invoking the keyword lookup with `K`.

The severity is rated Medium because Normal-mode `K` is not affected and
exploitation requires the victim to deliberately select the crafted text in
Visual mode and invoke the keyword lookup; the bug does not fire on
file-open alone.

## Acknowledgements

The Vim project would like to thank Github user @manus-use for reporting the issue.

## References

The issue has been fixed as of Vim patch [v9.2.0839](https://github.com/vim/vim/releases/tag/v9.2.0839).

- [Commit](https://github.com/vim/vim/commit/c5a82fe013e73c98004ad7cd4f906b1ad1ed610e)
- [Github Security Advisory](https://github.com/vim/vim/security/advisories/GHSA-r5v6-q6j8-8qw2)
}}}

{{{
Arbitrary Code Execution via Netrw Menu Construction in Vim < 9.2.0840
=======================================================================

Date: 23.07.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Improper Control of Generation of Code (CWE-94),
     Incomplete List of Disallowed Inputs (CWE-184)

## Summary

The netrw file browser builds its Bookmarks, History and Targets menus by
interpolating directory paths into `:execute`d `:menu` commands.  The paths
are escaped with the character set in `g:netrw_menu_escape`, which did not
include the Ex command separator `|`.  Because `:menu` treats an unescaped
bar as the end of the command, a directory path containing a bar terminates
the `:menu` command and the remainder of the path is executed as Ex
commands, and via `:!` as operating-system commands.  Two of the affected
sites additionally interpolate the path into a single-quoted Vim string
without neutralizing the quote.

## Description

`runtime/plugin/netrwPlugin.vim` loads the netrw package on startup, so no
opt-in is required.  While browsing, netrw records visited directories in
its history and rebuilds its menus, calling `s:NetrwBookmarkMenu()` and
`s:NetrwTgtMenu()` in `runtime/pack/dist/opt/netrw/autoload/netrw.vim`.
Those functions construct the menu entries by concatenation, for example:

    let bmd = escape(bmd, g:netrw_menu_escape)
    exe 'sil! menu ' .. ... .. 'Bookmarks.' .. bmd .. '    :e ' .. bmd .. ""\<cr>""

`g:netrw_menu_escape` defaulted to `'.&? \'`, which neutralizes characters
significant to menu rendering but not the bar.  The `:menu` command carries
the `EX_TRLBAR` attribute, so an unescaped bar in the interpolated path ends
the `:menu` command and everything after it is parsed as a further Ex
command.

The Targets menu entries additionally embed the path in a single-quoted Vim
string passed to `netrw#MakeTgt()` without escaping, so a path containing a
single quote can terminate that string early and inject Vim script.

Five construction sites were affected: the bookmark goto and bookmark delete
entries, the history entry, and the bookmark and history entries of the
Targets menu.

Menu construction is guarded by `has(""gui"")`, `has(""menu"")`,
`has(""gui_running"")`, the `'m'` flag in 'guioptions' and `g:netrw_menu`.
Vim running in a terminal is therefore not affected; the issue applies to
the GUI version with the menu bar enabled.

## Impact

Arbitrary Ex command execution, and via the `:!` command arbitrary
operating-system command execution, in the context of the user running Vim.
Exploitation requires:

- the GUI version of Vim with menus enabled (`has(""gui_running"")`, the `'m'`
  flag in 'guioptions' and `g:netrw_menu` set, which are the defaults),
- a directory path under the attacker's control, for example on a shared
  filesystem or a remote host browsed over FTP or SFTP,
- the victim browsing that path with netrw, or bookmarking it, so that it
  enters netrw's history or bookmark list and the menus are rebuilt.

The severity is rated Medium because the console version of Vim is not
affected and the crafted path must first be recorded in the bookmark list or
the browsing history.

## Acknowledgements

The Vim project would like to thank David Carliez for reporting the issue.

## References

The issue has been fixed as of Vim patch [v9.2.0840](https://github.com/vim/vim/releases/tag/v9.2.0840).

- [Commit](https://github.com/vim/vim/commit/29c6fd090d4520592f8be7d9ec81190edf25ef69)
- [Github Security Advisory](https://github.com/vim/vim/security/advisories/GHSA-rcr7-f3wr-22r2)
}}}

{{{
Heap Buffer Overflow in Text Property Handling in Vim < 9.2.0841
================================================================

Date: 23.07.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Integer Overflow or Wraparound (CWE-190),
     Heap-based Buffer Overflow (CWE-122)

## Summary

The number of text properties attached to a line is stored in the memline
as a 16-bit value.  When adding a property, `prop_add_one()` in
`src/textprop.c` computes the new count as `(uint16_t)(proplen + 1)`
without checking the existing count against the 16-bit ceiling.  On a line
that already holds 65535 text properties the increment wraps to zero, so
the buffer allocated for the rewritten line reserves no space for any
property records, while the existing records are then copied into it.  This
writes far past the end of the allocation.

## Description

Text properties are stored inline in the memline entry for a line, in the
layout `[text][NUL][prop_count][textprop_T...][vtext...]`, where
`prop_count` is a `uint16_t`.  When `prop_add()` adds a property,
`prop_add_one()` obtains the current count from `get_text_props()` and
computes the new one:

    uint16_t new_propcount = (uint16_t)(proplen + 1);

The size of the replacement line is then derived from that value:

    new_line_len = (int)textlen + (int)PROP_COUNT_SIZE
                    + new_propcount * (int)sizeof(textprop_T)
                    + vtext_total;
    newtext = alloc(new_line_len);

When `proplen` is already 65535, `proplen + 1` is 65536, which does not fit
in a `uint16_t` and truncates to zero.  The allocation therefore contains
room for the line text and the count field but for no property records at
all.  The subsequent copies, which move the existing records into the new
buffer, are driven by `proplen` rather than by the truncated count, so all
65535 existing records are written into a buffer sized for none of them.

The existing validation of the property block, added in patch 9.2.0670,
checks the structural consistency of the stored data but does not impose an
upper bound on the property count, so nothing prevents a line from reaching
65535 properties.

The data written past the allocation consists of the existing `textprop_T`
records, whose field values derive from the arguments of earlier
`prop_add()` calls.

## Impact

An out-of-bounds heap write of attacker-influenced data, which typically
results in a crash and may be usable for further exploitation.
Exploitation requires:

- Vim built with the `textprop` feature, which is included in the ""huge""
  feature set used by most distributions,
- 65536 text properties being added to a single line of a buffer, either by
  a Vim script the user runs, or by a plugin that derives text properties
  from data the attacker controls, such as the contents of an opened file.

The severity is rated Medium because reaching the 16-bit ceiling on a
single line does not occur in normal use and requires either a script
written for the purpose or a plugin driven with crafted input.

## Acknowledgements

The Vim project would like to thank Github user @Wang1rrr for reporting the issue.

## References

The issue has been fixed as of Vim patch [v9.2.0841](https://github.com/vim/vim/releases/tag/v9.2.0841).

- [Commit](https://github.com/vim/vim/commit/a9336b476fd1a182e3f79b5f83c0ffb04f8a922b)
- [Github Security Advisory](https://github.com/vim/vim/security/advisories/GHSA-hm4g-pjfx-m27j)
}}}

{{{
Stack Buffer Overflow in the Vim Socket Server in Vim < 9.2.0842
=================================================================

Date: 23.07.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Stack-based Buffer Overflow (CWE-121),
     Out-of-bounds Write (CWE-787)

## Summary

The socket server backend of Vim's client-server feature accepted an
unbounded number of client connections.  Every accepted connection becomes a
channel with its own file descriptor, and each wait cycle of the main loop
adds all channel descriptors to fixed-size structures: an `fd_set` when Vim
uses `select()`, or a stack array of `struct pollfd` sized for a small fixed
number of channels when Vim uses `poll()`.  Neither the number of accepted
clients nor the value of a descriptor was checked against those limits, so a
process able to connect to the server socket can make Vim write past the end
of a stack object.

## Description

A Vim server started with `--servername` and the socket backend listens on a
unix domain socket, or on a loopback address when a `channel:` address is
used.  Each accepted connection is turned into a channel by
`socketserver_accept()` in `src/socketserver.c` and linked into both the
client list and the global channel list, without any limit on the number of
clients.

On builds that use `select()`, `channel_select_setup()` in `src/channel.c`
adds every channel descriptor to an `fd_set` with `FD_SET()`.  An `fd_set`
holds a fixed number of descriptors, given by `FD_SETSIZE`, which is 1024 on
common systems.  A descriptor greater than or equal to that value writes
past the end of the set, and the following `select()` call causes the kernel
to read and write back beyond it as well.  The same unchecked pattern was
present in `channel_fill_wfds()`, `channel_select_check()` and in the client
loop of `socketserver_wait()`.

On builds that use `poll()` instead, `socketserver_wait()` and
`RealWaitForChar()` in `src/os_unix.c` collect the descriptors in a stack
array of `struct pollfd` dimensioned by `MAX_OPEN_CHANNELS`, which is ten.
Here no unusual descriptor numbers are required: the array is exceeded once
more than about ten clients are connected.

Reaching a descriptor number of 1024 or more on the `select()` path requires
the process limit on open files to be higher than that value, which is the
case for services and desktop sessions on current systems, but not where the
limit is left at 1024.  On the `poll()` path no such condition applies.

The issue has been addressed by limiting the number of simultaneously
accepted client connections, by checking descriptors against `FD_SETSIZE`
before adding them to an `fd_set`, and by sizing the `struct pollfd` arrays
for the new limit.

## Impact

An out-of-bounds write to a stack object.  On the builds shipped by most
distributions, which enable `_FORTIFY_SOURCE`, the affected library routine
detects the condition and terminates the process, so the practical result is
that the Vim server is killed and unsaved changes are lost.  On builds
without that hardening the write is a single bit at an offset determined by
the descriptor number, together with the kernel writing back past the set.

Exploitation requires:

- Vim built with the socket server backend of the client-server feature and
  running as a server, that is started with `--servername`,
- a process able to connect to that server: for the default unix domain
  socket, one running under the same user account, since the socket
  directory is only accessible to its owner; for a `channel:` address, any
  process on the local machine, since such addresses are bound to the
  loopback interface,
- on builds using `select()`, a limit on open files above 1024 and enough
  connections to exceed it; on builds using `poll()`, about ten
  connections.

No action by the user of the Vim server is required, since an idle server
reaches the affected code continuously.

The severity is rated Medium because the impact is limited to availability,
the attacker must already be able to reach the server socket, and on the
`select()` path a raised limit on open files is required as well.

## 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.0842](https://github.com/vim/vim/releases/tag/v9.2.0842).

- [Commit](https://github.com/vim/vim/commit/2e967091c3c78cab4524609aa67fbca49e10a32d)
- [Github Security Advisory](https://github.com/vim/vim/security/advisories/GHSA-49m8-wwxj-mr69)
}}}

{{{
Out-of-bounds Access in Popup Opacity Handling in Vim >= 9.2.0469 && Vim < 9.2.0843
===================================================================================

Date: 23.07.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Buffer Underwrite (CWE-124),
     Out-of-bounds Read (CWE-125)

## Summary

A popup window created with the ""clipwindow"" option is clipped to its host
window rather than to the screen.  When such a popup is anchored to a text
property and the host window is scrolled so that the anchor moves above the
visible area, the popup's window row is negative by design, and the rows
clipped off the top are recorded separately.  The code that marks the screen
cells covered by a popup using the ""opacity"" option did not account for
this: it iterated from the popup's window row without a lower bound, so it
indexed the screen-sized array before its start.  This causes a read outside
the allocated array, and a write outside it when the stored value is smaller
than the popup's z-index.

## Description

`popup_mark_opacity_zindex()` in `src/popupwin.c` fills an array holding, for
each screen cell, the highest z-index of an opacity popup covering that
cell.  The array is allocated for the current screen size, and the cell
offset is computed as the row multiplied by the number of screen columns
plus the column.

The loop over the popup's rows was bounded above, by the popup height and by
the number of screen rows, but not below.  For a ""clipwindow"" popup whose
anchor has scrolled above the top of the host window, the window row is
negative, so the computed offset is negative as well and refers to memory
before the array.  The value found there is compared with the popup's
z-index, which is set from Vim script, and overwritten when it is smaller.

The column dimension is not affected, because the popup's window column is
always clamped to a non-negative value.  A related function that reads the
same array checks its arguments before indexing, so only the marking code
was affected.

The issue has been addressed by making the popup's window row always refer
to the first visible row, and recording the rows clipped off the top only in
the separate top offset, so that no consumer of the window row has to clamp
it.

## Impact

A read outside the bounds of a heap array, and a conditional write of a
16-bit value outside it.  The written value comes from the popup's z-index
and the affected offsets follow from the scroll position and the popup
geometry, so both are influenced by the Vim script that creates the popup.
In a default layout the accesses fall into a neighbouring array used for the
popup mask, and the editor continues to run, so the effect is silent.

Exploitation requires Vim script that creates a popup using the
""clipwindow"", ""opacity"" and text property anchor options together, and a
host window that is scrolled so the anchor leaves the visible area.  The
issue is therefore reachable from a plugin or from a script the user runs,
but not from opening a file, since a modeline cannot call functions.

The severity is rated Medium because the affected code can only be reached
by running Vim script, and because the write is constrained: it stores a
16-bit value and only where the value already present is smaller, so it can
raise the affected memory but not set it to an arbitrary value.

## 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.0843](https://github.com/vim/vim/releases/tag/v9.2.0843).

- [Commit](https://github.com/vim/vim/commit/975e191dc817d8d00abca7197c4529a417c2f805)
- [Github Security Advisory](https://github.com/vim/vim/security/advisories/GHSA-pmvp-6rcj-98p4)
}}}
"	enhancement	new	normal	13.1	Book	git	normal			
