[LFS Trac] #5940: vim-9.2.0513 (Security Update)

"LFS Trac" ([email protected] via lfs-book Mailing List) <[email protected]>
Newsgroups gmane.linux.lfs.book
Message-ID <[email protected]>
#5940: vim-9.2.0513 (Security Update)
-----------------------------+----------------------
 Reporter:  Douglas R. Reno  |      Owner:  lfs-book
     Type:  enhancement      |     Status:  new
 Priority:  high             |  Milestone:  13.1
Component:  Book             |    Version:  git
 Severity:  normal           |   Keywords:
-----------------------------+----------------------
 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)
 }}}
-- 
Ticket URL: <https://wiki.linuxfromscratch.org/lfs/ticket/5940>
LFS Trac <https://wiki.linuxfromscratch.org/lfs/>
Linux From Scratch: Your Distro, Your Rules.

-- 
http://lists.linuxfromscratch.org/sympa/info/lfs-book
Unsubscribe: See the above information page
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.