[LFS Trac] #5956: vim-9.2.0663 (Security Update)

"LFS Trac" ([email protected] via lfs-book Mailing List) <[email protected]> Wed, 17 Jun 2026 18:55:20 -0000
Newsgroups gmane.linux.lfs.book
Message-ID <[email protected]>
#5956: vim-9.2.0663 (Security Update)
-------------------------+----------------------
 Reporter:  Joe Locash   |      Owner:  lfs-book
     Type:  enhancement  |     Status:  new
 Priority:  normal       |  Milestone:  13.1
Component:  Book         |    Version:  git
 Severity:  normal       |   Keywords:
-------------------------+----------------------
 There have been a few security updates since the last book update:

 {{{
 Out-of-bounds Write in Spell File Word Count in Vim < 9.2.0653
 ==============================================================
 Date: 15.06.2026
 Severity: Medium
 CVE: *requested, not yet assigned*
 CWE: Out-of-bounds Write (CWE-787)

 ## Summary
 The `tree_count_words()` function in `src/spellfile.c` fills in the word-
 count
 fields of a spell-file word trie by walking it iteratively with a depth
 counter.  The counter is bounded only by the trie structure itself; it is
 never checked against the size of the fixed `MAXWLEN`-element stack arrays
 it
 indexes (`arridx[]`, `curi[]`, `wordcount[]`).  A crafted `.spl`/`.sug`
 file
 pair, loaded when the user invokes spell suggestion, can drive the descent
 arbitrarily deep, so the function writes past the end of those arrays.
 This
 is a stack out-of-bounds write that corrupts the call frame and crashes
 the
 editor.

 ## Description
 `tree_count_words()` is called from `suggest_load_files()` when spell
 suggestion loads a language's `.sug` file (for example on `z=`,
 `:spellsuggest`, or suggestion completion).  For each node it descends one
 level with:
 ```C
     else
     {
         ++depth;
         arridx[depth] = idxs[n];
         curi[depth] = 1;
         wordcount[depth] = 0;
     }
 ```

 The three arrays have `MAXWLEN` (254) elements, so any `depth` of 254 or
 more
 writes out of bounds.  In a well-formed file each trie level corresponds
 to
 one byte of a word, so depth is naturally limited, but the reader does not
 enforce this for shared subtrees: `read_tree_node()` caps inline recursion
 at
 `depth > MAXWLEN`, yet a `BY_INDEX` shared reference is accepted (its
 target
 index is range-checked) and is *not* recursed into.  A trie that uses
 shared
 references to form a cycle, or a deep forward-shared chain, therefore
 parses
 cleanly while driving the iterative walker past `MAXWLEN`.

 ## Impact
 A spell file is normally inert data, but Vim resolves `spelllang`,
 `spellfile`, and `runtimepath` to load it, so a repository or archive that
 ships a malicious `spell/` sidecar can deliver the crafted pair.  The
 trigger
 is user-interaction-gated: spell checking must be enabled and the user
 must
 invoke spell suggestion on a misspelled word.  When that happens, the
 out-of-bounds write corrupts the `tree_count_words()` stack frame.  On
 builds
 compiled with stack protection the overwrite is caught at the function
 epilogue
 and the process aborts; cyclic geometries instead walk into the stack
 guard
 page and causes a crash.

 ## Acknowledgements
 The Vim project would like to thank Cipher / Causal Security
 (https://causalsecurity.com/) for reporting and analyzing the issue and
 suggesting a fix.

 ## References
 The issue has been fixed as of Vim patch
 [v9.2.0653](https://github.com/vim/vim/releases/tag/v9.2.0653).
 -
 [Commit](https://github.com/vim/vim/commit/a80874d9b84a01040e3d1aef2d4a59e1934dafb7)
 - [Github Security
 Advisory](https://github.com/vim/vim/security/advisories/GHSA-
 wgh4-64f7-q3jq)
 }}}


 {{{
 Out-of-bounds Write in Spell File Prefix Dump in Vim < 9.2.0662
 ===============================================================
 Date: 16.06.2026
 Severity: Medium
 CVE: *requested, not yet assigned*
 CWE: Out-of-bounds Write (CWE-787)

 ## Summary
 The `dump_prefixes()` function in `src/spell.c` walks a spell-file prefix
 trie
 iteratively with a depth counter while dumping the prefixes that apply to
 a
 word.  The counter is bounded only by the trie structure itself; it is
 never
 checked against the size of the fixed `MAXWLEN`-element stack arrays it
 indexes
 (`prefix[]`, `arridx[]`, `curi[]`).  A crafted `.spl` file, loaded when
 the
 user dumps the word list, can drive the descent arbitrarily deep, so the
 function writes past the end of those arrays.  This is a stack out-of-
 bounds
 write that corrupts the call frame and crashes the editor.

 ## Description
 `dump_prefixes()` is called from `spell_dump_compl()` when the word list
 is
 dumped, for example on `:spelldump` or via spelling completion.  For each
 node
 it descends one level with:
 ```C
     else
     {
         prefix[depth++] = c;
         arridx[depth] = idxs[n];
         curi[depth] = 1;
     }
 ```
 The arrays have `MAXWLEN` (254) elements, so any `depth` of 254 or more
 writes
 out of bounds; a second sink underflows a `size_t` length passed to
 `vim_strncpy()` once `depth` reaches `MAXWLEN`.  In a well-formed file
 each
 trie level corresponds to one byte of a prefix, so depth is naturally
 limited,
 but the reader does not enforce this for shared subtrees: a `BY_INDEX`
 shared
 reference is accepted (its target index is range-checked) and is *not*
 recursed
 into.  A prefix trie that uses a shared reference to point back to an
 ancestor
 or itself therefore parses cleanly while driving the iterative walker past
 `MAXWLEN`.  This is the same class of issue as
 [GHSA-wgh4-64f7-q3jq](https://github.com/vim/vim/security/advisories/GHSA-
 wgh4-64f7-q3jq)
 (`tree_count_words()`, fixed in 9.2.0653) in a sibling trie walker that
 was
 left unguarded.

 ## Impact
 A spell file is normally inert data, but Vim resolves `spelllang`,
 `spellfile`,
 and `runtimepath` to load it, so a repository or archive that ships a
 malicious
 `spell/` sidecar can deliver the crafted file.  The trigger is
 user-interaction-gated: spell checking must be enabled and the user must
 dump
 the word list.  When that happens, the out-of-bounds write corrupts the
 `dump_prefixes()` stack frame.

 ## Acknowledgements
 The Vim project would like to thank Cipher / Causal Security
 (https://causalsecurity.com/) for reporting and analyzing the issue and
 suggesting a fix.

 ## References
 The issue has been fixed as of Vim patch
 [v9.2.0662](https://github.com/vim/vim/releases/tag/v9.2.0662).
 - [Commit](https://github.com/vim/vim/commit/8325b193bba5f01e7a7d8241f)
 - [Github Security
 Advisory](https://github.com/vim/vim/security/advisories/GHSA-qm9w-fmpj-
 879h)
 }}}


 {{{
 Vimscript Code Injection in netrw NetrwLocalRmFile() via crafted filename
 affects Vim < 9.2.0663
 ================================================================================================
 Date: 16.06.2026
 Severity: Medium
 CVE: *requested, not yet assigned*
 CWE: Improper Control of Generation of Code (CWE-94) /
      Improper Neutralization of Special Elements used in an OS Command
 ('OS Command Injection') (CWE-78)

 ## Summary
 A Vimscript code injection vulnerability exists in `s:NetrwLocalRmFile()`
 in
 the netrw plugin (`runtime/pack/dist/opt/netrw/autoload/netrw.vim`) when
 deleting a local file from the browser.  A filename derived from the
 buffer's
 directory listing is interpolated into an Ex command line passed to
 `:execute` with only the backslash character escaped, allowing a crafted
 filename containing a bar (`|`) to terminate the intended command and
 execute
 arbitrary Vimscript, including shell commands via `:call system()` and
 `:!`.

 ## Description
 `s:NetrwLocalRmFile()` removes a file and wipes its buffer.  The sibling
 sinks
 in the same file guard the Ex context with `fnameescape()`, for example:

     exe "sil! keepj keepalt file ".fnameescape(a:newname)

 The delete handler, however, escapes only the backslash character and
 passes
 the value straight to `:execute`:

     let rmfile = s:NetrwFile(netrw#fs#ComposePath(a:path,
                    escape(a:fname, '\\')))->fnamemodify(':.')
     ...
     execute printf('silent! bwipeout %s', rmfile)

 `escape(a:fname, '\\')` neutralizes only `\`; the subsequent
 `ComposePath`,
 `NetrwFile`, and `fnamemodify` calls join and normalize the path but do
 not
 remove `|` or a newline.  When the value reaches `:execute`, a `|`
 terminates
 the `bwipeout` command and begins the next, so the remainder of the
 filename
 is run as Ex commands.  A file named `x|call system('cmd')|y` turns the
 deletion into `silent! bwipeout x`, `call system('cmd')`, `y`, and the
 injected `:call system(...)` runs an arbitrary shell command.
 The filename reaches `s:NetrwLocalRmFile()` through the `D` mapping, which
 reads the filename from the current line of the netrw directory listing
 and,
 after confirmation, deletes the entry.

 ## 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 bar (`|`),
 - a crafted file present in a directory the victim browses with netrw, and
 - the victim to delete that specific entry (press `D`, then confirm with
 `y`).

 The severity is rated Medium because exploitation requires a planted file
 with
 an unusual name and a deliberate delete action by the victim on that
 specific
 entry, although the resulting primitive is full command execution as the
 victim user.
 Note: due to the nature of the issue, it seems unlikely that a user would
 delete such a suspicious filename.

 ## Acknowledgements
 The Vim project would like to thank Cipher / Causal Security
 (https://causalsecurity.com/) for reporting and analyzing the issue.

 ## References
 The issue has been fixed as of Vim patch
 [v9.2.0663](https://github.com/vim/vim/releases/tag/v9.2.0663).
 -
 [Commit](https://github.com/vim/vim/commit/55bc757a5d436e59d50fe43f7cda94b118f86cb2)
 - [Github Security
 Advisory](https://github.com/vim/vim/security/advisories/GHSA-vhh8-v6wx-
 hjjh)
 }}}
-- 
Ticket URL: <https://wiki.linuxfromscratch.org/lfs/ticket/5956>
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