﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	severity	resolution	keywords	cc
5940	vim-9.2.0513 (Security Update)	Douglas R. Reno	lfs-book	"This fixes three security vulnerabilities so far:

**CVE-2026-47167**

{{{
Vimscript Code Injection in netrw NetrwBookHistSave() via crafted directory name affects Vim < 9.2.495
======================================================================================================
Date: 17.05.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Improper Control of Generation of Code (CWE-94) /
     Improper Neutralization of Special Elements in Output Used by a Downstream Component (CWE-74)

## Summary

A Vimscript code injection vulnerability exists in `s:NetrwBookHistSave()`
in the netrw plugin (`runtime/pack/dist/opt/netrw/autoload/netrw.vim`)
when serializing browsed directory paths to the history file
`~/.vim/.netrwhist`.  A directory name derived from the filesystem is
interpolated into a single-quoted Vimscript string literal without
escaping embedded single quotes, allowing a crafted directory name to
break out of the string context and execute arbitrary Vimscript,
including shell commands via `system()` and `:!`, the next time the
history file is sourced.

## Description

netrw records every directory the user browses into a per-user history
file at `~/.vim/.netrwhist`.  `s:NetrwBookHistSave()` writes each entry
as a Vimscript assignment statement:

    call setline(lastline,'let g:netrw_dirhist_'.cnt.""='"".g:netrw_dirhist_{cnt}.""'"")

The directory path `g:netrw_dirhist_{cnt}` is inserted between two
literal `'` characters without escaping any single quotes contained in
the path, an embedded single quote therefore terminates the string
early, after which the remainder of the path is parsed as additional
Vimscript statement.  Vim statements may be chained with `|`, so a directory name
of the form

    x'|<injected Vimscript>|let y='z

is serialized as three valid statements on a single line.

The sibling bookmark serializer thirty lines below in the same function
uses `string()` correctly, which is the canonical primitive for this
purpose; only the history serializer was missing the escape.

The history file is read back on every netrw initialization with:

    exe ""keepalt NetrwKeepj so "".savefile

The `:source` invocation evaluates every statement in the file, so any
injected Vimscript executes with the privileges of the user running
Vim.  Calls such as `system()`, `:!`, or `writefile()` in the injected
fragment yield arbitrary command execution.

The directory name reaches `s:NetrwBookHistSave()` through the normal
netrw browse flow: when the user navigates into a directory via netrw,
the path is appended to the in-memory history list, which is flushed to
disk by an autocmd on `VimLeave`.  The injection therefore arms on any
netrw browse of a maliciously named directory and fires on any
subsequent Vim invocation that opens a directory through netrw.

The default configuration is affected: `g:netrw_dirhistmax` defaults to
10, which enables the history mechanism.

POSIX forbids `/` inside a single filename component, so the dirname
payload cannot directly construct an absolute path; this constraint is
bypassed via environment-variable expansion (e.g. `$HOME`) or relative
paths evaluated at Vim's current working directory.

## Impact

The vulnerability allows arbitrary Vimscript execution, and by
extension arbitrary shell command execution, with the privileges of the
user running Vim.  Exploitation requires:

- a Unix-like system on which a filename may contain a single quote,
- a crafted directory present in a location the victim browses with
  netrw (e.g. delivered via a cloned repository, extracted archive, or
  shared filesystem), and
- the victim to (1) browse the crafted directory once with netrw, then
  (2) launch Vim on any directory at a later point so that
  `.netrwhist` is sourced.

The severity is rated Medium because exploitation requires a planted
directory name with an unusual name and a deliberate ""edit directory"" command
by the victim, although the resulting primitive is full
command execution as the victim user.

The injection persists in `.netrwhist` until the entry is rotated out of
the history.

## Acknowledgements

The Vim project would like to thank Srinivas Piskala Ganesh Babu for
reporting and analyzing the issue and suggesting a fix.

## References

The issue has been fixed as of Vim patch [v9.2.0495](https://github.com/vim/vim/releases/tag/v9.2.0495).

- [Commit](https://github.com/vim/vim/commit/f08ab2f4d7d2947c8dd6c179ae08ee6146a2694b)
- [Github Security Advisory](https://github.com/vim/vim/security/advisories/GHSA-crm5-rh6j-2c7c)
}}}

**CVE-2026-47162**

{{{


Vimscript Code Injection in cucumber filetype plugin via crafted step-definition regex affects Vim < 9.2.0496
=============================================================================================================
Date: 17.05.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Improper Control of Generation of Code (CWE-94) /
     Improper Neutralization of Directives in Dynamically Evaluated Code (CWE-95)

## Summary

A code injection vulnerability exists in `s:stepmatch()` in the
cucumber filetype plugin (`runtime/ftplugin/cucumber.vim`) on Vim builds
with `+ruby` support.  Step-definition patterns read from `.rb` files
under the repository's `features/*/` or `stories/*/` directories are
embedded into a Ruby `Kernel.eval` argument without sufficient escaping,
allowing a crafted pattern in an attacker-controlled repository to
execute arbitrary Ruby (and through it arbitrary shell commands) when
the user invokes a step-jump mapping (`[d`, `]d`).

## Description

The cucumber ftplugin's step-jump mappings call `s:steps()` which in
turn calls `s:stepmatch()` for every step definition discovered by
`s:allsteps()`.  For regex-style step patterns delimited by `/.../`,
`s:stepmatch()` falls back to Ruby evaluation when Vim's own regex
engine cannot match:

    if has(""ruby"") && pattern !~ '\\\@<!#{'
      ruby VIM.command(""return #{if (begin;
        Kernel.eval('/'+VIM.evaluate('pattern')+'/');
      rescue SyntaxError; end) === VIM.evaluate('a:target')
      then 1 else 0 end}"")

The pattern value is concatenated into the Ruby source passed to
`Kernel.eval`.  The `#{` guard rejects Ruby string-interpolation
sequences but does not prevent the pattern from terminating the regex
literal with `/` and appending arbitrary Ruby statements.  A pattern of
the form

    x/; system(""touch marker""); #

is evaluated by Ruby as a regex literal, a `system()` call, and a
comment — three valid expressions chained on one line.  `system()`
runs with the privileges of the user running Vim.

The pattern reaches `s:stepmatch()` through `s:allsteps()`, which
scans `.rb` files matching `b:cucumber_steps_glob` (by default
`features/*/*.rb` and `stories/*/*.rb`) for any line resembling a step
definition.  The injection therefore arms whenever a cucumber-style
repository under the working directory contains an attacker-controlled
`.rb` file, and fires the first time the victim invokes a step-jump
mapping on a step whose target text the planted regex matches.

The omni-completion path (`CucumberComplete()`) uses `s:allsteps()`
directly without going through `s:stepmatch()`, so completion alone
does not trigger the vulnerability.

## Impact

The vulnerability allows arbitrary Ruby execution, and by extension
arbitrary shell command execution, with the privileges of the user
running Vim.  Exploitation requires:

- a Vim build compiled with `+ruby` support,
- a cucumber-style repository (with `features/` or `stories/`
  subdirectories containing `.rb` step definitions) opened by the
  victim, and
- the victim to invoke a step-jump mapping (`[d` or `]d`) on a
  feature line whose target text is matched by the crafted regex.

The severity is rated Medium because exploitation requires a `+ruby`
build (not the default in many distributions), an attacker-planted
step-definition file with an unusual pattern syntax, and a deliberate
step-jump action by the victim on a feature line that the planted
regex matches, although the resulting primitive is full command
execution as the victim user.

## Acknowledgements

The Vim project would like to thank Aisle Research for reporting and
analyzing the issue.

## References

The issue has been fixed as of Vim patch
[v9.2.0496](https://github.com/vim/vim/releases/tag/v9.2.0496).

- [Commit](https://github.com/vim/vim/commit/a65a52d684bc58535ad28a4ae824d22e76399934)
- [Github Security Advisory](https://github.com/vim/vim/security/advisories/GHSA-4473-94jm-w5x9)
}}}

**CVE Not Yet Assigned**

{{{
Multiple Memory Safety Issues in Vim Spell File Parser affects Vim < 9.2.0513
=============================================================================
Date: 22.05.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Out-of-bounds Read (CWE-125),
     Use of Uninitialized Resource (CWE-908),
     Uncontrolled Recursion (CWE-674)

## Summary
Three related memory-safety issues exist in the Vim spell file (`.spl`)
parser in `src/spellfile.c`.  A crafted spell file can cause:

1. a heap out-of-bounds read in `read_tree_node()` via a `BY_INDEX`
   shared tree node that references an uninitialized array position,
2. a one-byte heap out-of-bounds read in `tree_count_words()` past the
   end of the word-tree byte array, and
3. a stack overflow in `read_tree_node()` through uncontrolled recursion
   on a deep linear node chain.

Because the `'spelllang'` option can be set from a modeline, a text
file modeline can trigger spell file loading if a malicious `.spl` file
has been planted on the runtimepath, which can happen when cloning a vim
package.

## Description

### 1. Uninitialized shared-node target in read_tree_node()
In `spell_read_tree()` the byte array `bp` for a word tree was allocated
with `alloc(len)` and not zero-initialized, while the companion index
array used `lalloc_clear()`.  The tree parser validated `BY_INDEX`
shared-node references only against `maxidx` (the allocated array
size), not against positions that were actually written by
`read_tree_node()`.  A crafted file can declare a `<nodecount>` larger
than the tree it serializes and include a `BY_INDEX` reference into the
unwritten tail, leaving `byts[N]` containing uninitialized heap data.

On `z=` (spell suggest) or `spellsuggest()`, the suggestion walk reads
`byts[arridx]` as a sibling count and iterates that many slots,
producing a further out-of-bounds heap read with an attacker-influenced
length.

### 2. Missing length guard in tree_count_words()
`tree_count_words()` skipped runs of trailing NUL siblings with
`while (byts[n + 1] == 0)` and had no length guard.  The structurally
identical loop in `sug_filltree()` already carried
`n + 1 < slang->sl_fbyts_len && ...` with the explicit comment
""But don't go over the end.""; that guard had not been propagated to
`tree_count_words()`.  When called during `.sug` file loading on a
tree whose final sibling is `BY_NOFLAGS`, the walk reads one byte past
the end of the byts array.

### 3. Uncontrolled recursion in read_tree_node()
`read_tree_node()` recursed once per non-shared, non-end-of-word
sibling without a depth limit.  A crafted `.spl` file containing a
linear chain of nodes (siblingcount=1, non-NUL byte at each level)
drives the recursion to a depth bounded only by the declared
`<nodecount>` (a 4-byte field).  On default 8 MB stacks, approximately
88,000 nested frames exhaust the stack and crash Vim with SIGSEGV.

## Impact
Issues 1 and 2 are out-of-bounds heap reads with attacker-influenced
range; the practical outcome is a crash of the Vim process and a small
window of uninitialized or adjacent heap data being consumed by the
suggestion algorithm.  Issue 3 reliably crashes Vim through stack
exhaustion.

Exploitation requires a malicious `.spl` file to be present on the
runtimepath and the victim to either:

- explicitly enable spell checking with the matching language
- open any text file containing a modeline that sets `'spelllang'` and
  enables `'spell'`, while `'modeline'` is enabled.

The severity is rated Medium because exploitation requires both a
planted spell file and a separate triggering action by the victim, and
the practical outcome is a crash rather than code execution.

## Acknowledgements
The Vim project would like to thank github user tacdm for reporting and
analyzing the issues and suggesting fixes.

## References
The issues have been fixed as of Vim patch [v9.2.0513](https://github.com/vim/vim/releases/tag/v9.2.0513).
- [Commit](https://github.com/vim/vim/commit/25e4e46c584840806b45da20ed)
- [Github Security Advisory](https://github.com/vim/vim/security/advisories/GHSA-3h95-3962-mmvf)
}}}"	enhancement	new	high	13.1	Book	git	normal			
