CVE-2026-47162
Description
A Vimscript code injection vulnerability in netrw's history serializer allows arbitrary command execution when Vim sources a maliciously crafted directory name.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A Vimscript code injection vulnerability in netrw's history serializer allows arbitrary command execution when Vim sources a maliciously crafted directory name.
Vulnerability
A Vimscript code injection vulnerability exists in the s:NetrwBookHistSave() function of the netrw plugin (runtime/pack/dist/opt/netrw/autoload/netrw.vim) in Vim versions prior to 9.2.0495. When serializing browsed directory paths to the history file ~/.vim/.netrwhist, the directory name is interpolated into a single-quoted Vimscript string literal without escaping embedded single quotes [1]. This allows a crafted directory name to break out of the string context and inject arbitrary Vimscript code. The issue was introduced because the code directly inserts the directory path into the string '...' rather than using the string() function, which correctly escapes values [2].
Exploitation
An attacker must be able to influence a directory name that a victim user will browse to in Vim using netrw. This could be achieved by creating a directory with a specially crafted name on a local filesystem (e.g., via shared hosting, a USB drive, or a network share) or by tricking the user into browsing a malicious remote path over FTP/SCP that netrw automatically records. The crafted directory name includes single quotes and Vimscript statements separated by pipe characters (e.g., x'||let y='z) [1]. When the user later reopens Vim, the history file is sourced via :source, executing the injected Vimscript with the user's privileges. No additional authentication or special privileges beyond filesystem write access to create the directory are required.
Impact
Successful exploitation results in arbitrary Vimscript execution, which can invoke shell commands via system() or :!, write arbitrary files with writefile(), or otherwise compromise the user's system. The attacker gains code execution at the privilege level of the user running Vim, which could lead to full system compromise depending on the user's permissions [1].
Mitigation
The vulnerability is fixed in Vim version 9.2.0495, released on 17 May 2026 [3]. Users should upgrade Vim to this version or later. The fix changes the serialization in s:NetrwBookHistSave() to use string(g:netrw_dirhist_{cnt}) instead of the string literal concatenation, properly escaping single quotes and preventing code injection [2]. There is no viable workaround other than upgrading, as disabling netrw or blocking history file sourcing would degrade functionality. The issue is not listed on the CISA KEV as of the publication date.
AI Insight generated on Jun 11, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
1f08ab2f4d7d2patch 9.2.0495: [security]: runtime(netrw): code injection via NetrwBookHistSave()
3 files changed · +24 −2
runtime/pack/dist/opt/netrw/autoload/netrw.vim+2 −2 modified@@ -1,7 +1,7 @@ " Creator: Charles E Campbell " Previous Maintainer: Luca Saccarola <github.e41mv@aleeas.com> " Maintainer: This runtime file is looking for a new maintainer. -" Last Change: 2026 May 14 +" Last Change: 2026 May 17 " Copyright: Copyright (C) 2016 Charles E. Campbell {{{1 " Permission is hereby granted to use and distribute this code, " with or without modifications, provided that this copyright @@ -2935,7 +2935,7 @@ function s:NetrwBookHistSave() while ( first || cnt != g:netrw_dirhistcnt ) let lastline= lastline + 1 if exists("g:netrw_dirhist_{cnt}") - call setline(lastline,'let g:netrw_dirhist_'.cnt."='".g:netrw_dirhist_{cnt}."'") + call setline(lastline,'let g:netrw_dirhist_'.cnt.'='.string(g:netrw_dirhist_{cnt})) endif let first = 0 let cnt = ( cnt - 1 ) % g:netrw_dirhistmax
src/testdir/test_plugin_netrw.vim+20 −0 modified@@ -760,4 +760,24 @@ function Test_netrw_NetrwMaps_CR_dirname() unlet! g:netrw_pwn bw! endfunction + +func Test_netrw_injection() + let g:netrw_home = getcwd() + let savefile = g:netrw_home . '/.netrwhist' + let g:netrw_dirhistmax = 10 + let g:netrw_dirhistcnt = 1 + let g:netrw_dirhist_1 = "x'|let g:injected = 1|let y='z" + call delete(savefile) + try + call netrw#Call('NetrwBookHistSave') + call assert_true(filereadable(savefile), savefile . ' must be written') + unlet g:netrw_dirhist_1 + execute 'source ' . fnameescape(savefile) + call assert_false(exists("g:injected"), 'injected statement must not execute') + call assert_equal("x'|let g:injected = 1|let y='z", g:netrw_dirhist_1, 'dirname must round-trip') + finally + call delete(savefile) + unlet! g:netrw_home g:netrw_dirhistmax g:netrw_dirhistcnt g:netrw_dirhist_1 g:injected + endtry +endfunc " vim:ts=8 sts=2 sw=2 et
src/version.c+2 −0 modified@@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 495, /**/ 494, /**/
Vulnerability mechanics
Root cause
"Missing escaping of single quotes in Vimscript string interpolation allows code injection via crafted directory names."
Attack vector
An attacker who can create a directory with a crafted name (e.g., containing a single quote followed by Vimscript commands) on a filesystem that a victim browses with netrw will cause that name to be written unescaped into the history file. When Vim sources the history file on the next startup, the injected Vimscript executes, allowing arbitrary command execution via `system()` or `:!` [ref_id=1]. The precondition is that the victim must navigate into the attacker-controlled directory using netrw.
Affected code
The vulnerability resides in `s:NetrwBookHistSave()` within `runtime/pack/dist/opt/netrw/autoload/netrw.vim`. The function serializes directory paths into the history file `~/.vim/.netrwhist` using single-quoted Vimscript string literals without escaping embedded single quotes [patch_id=5620677].
What the fix does
The patch replaces the single-quoted string interpolation with `string()` — a Vim built-in that properly escapes special characters for safe inclusion in Vimscript source. The old code `"'" . g:netrw_dirhist_{cnt} . "'"` allowed a directory name containing a single quote to break out of the string literal; the new code `'=' . string(...)` produces a correctly quoted representation that cannot be escaped [patch_id=5620677]. The included test confirms that a payload like `x'|let g:injected = 1|let y='z` no longer executes when the history file is sourced.
Preconditions
- inputVictim must browse an attacker-controlled directory with netrw
- inputAttacker must be able to create a directory with a crafted name on a filesystem accessible to the victim
Generated on Jun 11, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
0No linked articles in our index yet.