Fix CVE-2026-47162: netrw code injection via NetrwBookHistSave()

Backport upstream patch 9.2.0495 (commit f08ab2f4d7d2) to fix
CVE-2026-47162 — code injection via NetrwBookHistSave() in the
netrw plugin.

The vulnerable setline() call in s:NetrwBookHistSave() used naive
string concatenation to build Vimscript let statements, allowing
code injection through crafted directory names. The fix replaces
this with string() for proper quoting.

The patch was adjusted for the RHEL 9 Vim 8.2 codebase: netrw
path changed from runtime/pack/dist/opt/netrw/autoload/ to
runtime/autoload/, and a new test file was added.

CVE: CVE-2026-47162
Upstream patches:
 - f08ab2f4d7.patch
Resolves: RHEL-186655

This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.

Assisted-by: Ymir
This commit is contained in:
RHEL Packaging Agent 2026-07-30 13:06:41 +00:00 committed by Zdenek Dohnal
parent ed8b07e0b5
commit 12deb611d3
2 changed files with 90 additions and 1 deletions

View File

@ -0,0 +1,79 @@
From 952ef64dbdc6939d8beb59ce1304f231debc52e2 Mon Sep 17 00:00:00 2001
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
Date: Thu, 30 Jul 2026 12:30:41 +0000
Subject: [PATCH] patch 9.2.0495: [security]: runtime(netrw): code injection
via NetrwBookHistSave()
Problem: [security]: runtime(netrw): code injection via
NetrwBookHistSave()
Solution: Properly quote the directory name using string() function
(Srinivas Piskala Ganesh Babu)
Github Security Advisory:
https://github.com/vim/vim/security/advisories/GHSA-crm5-rh6j-2c7c
---
runtime/autoload/netrw.vim | 2 +-
src/testdir/Make_all.mak | 2 ++
src/testdir/test_plugin_netrw.vim | 20 ++++++++++++++++++++
3 files changed, 23 insertions(+), 1 deletion(-)
create mode 100644 src/testdir/test_plugin_netrw.vim
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index 5fd08ac..41893e2 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -3736,7 +3736,7 @@ fun! 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}))
" call Decho("..".lastline.'let g:netrw_dirhist_'.cnt."='".g:netrw_dirhist_{cnt}."'",'~'.expand("<slnum>"))
endif
let first = 0
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index 7fd4e89..1709886 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -209,6 +209,7 @@ NEW_TESTS = \
test_perl \
test_plugin_ccomplete \
+ test_plugin_netrw \
test_plugin_tar \
test_plugin_phpcomplete \
test_plugin_python3complete \
test_plus_arg_edit \
@@ -448,6 +449,7 @@ NEW_TESTS_RES = \
test_perl.res \
test_plugin_ccomplete.res \
+ test_plugin_netrw.res \
test_plugin_tar.res \
test_plugin_phpcomplete.res \
test_plugin_python3complete.res \
test_plus_arg_edit.res \
diff --git a/src/testdir/test_plugin_netrw.vim b/src/testdir/test_plugin_netrw.vim
new file mode 100644
index 0000000..d840905
--- /dev/null
+++ b/src/testdir/test_plugin_netrw.vim
@@ -0,0 +1,20 @@
+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

View File

@ -27,7 +27,7 @@ Summary: The VIM editor
URL: http://www.vim.org/
Name: vim
Version: %{baseversion}.%{patchlevel}
Release: 38%{?dist}
Release: 39%{?dist}
License: Vim and MIT
Source0: ftp://ftp.vim.org/pub/vim/unix/vim-%{baseversion}-%{patchlevel}.tar.bz2
Source1: virc
@ -233,6 +233,11 @@ Patch3077: 0001-patch-9.2.0653-security-out-of-bounds-write-in-tree_.patch
# adapted test for Vim 8.2 (added source check.vim, replaced defer with manual cleanup),
# kept self.params instead of upstream safe_params (prior hardening commit not present)
Patch3078: 0001-patch-9.2.0699-security-possible-code-execution-with.patch
# RHEL-186655 CVE-2026-47162 runtime(netrw): code injection via NetrwBookHistSave()
# https://redhat.atlassian.net/browse/RHEL-186655
# https://github.com/vim/vim/commit/f08ab2f4d7d2947c8dd6c179ae08ee6146a2694b
# adjusted: netrw path changed from runtime/pack/dist/opt/netrw/autoload/ to runtime/autoload/ (Vim 8.2)
Patch3079: 0001-patch-9.2.0495-security-runtime-netrw-code-injectio.patch
# gcc is no longer in buildroot by default
@ -499,6 +504,7 @@ perl -pi -e "s,bin/nawk,bin/awk,g" runtime/tools/mve.awk
%patch -P 3076 -p1 -b .soundfold-overflow
%patch -P 3077 -p1 -b .tree-count-words-oob
%patch -P 3078 -p1 -b .python-complete-repr
%patch -P 3079 -p1 -b .netrw-book-hist-inject
%build
cd src
@ -1051,6 +1057,10 @@ touch %{buildroot}/%{_datadir}/%{name}/vimfiles/doc/tags
%endif
%changelog
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:8.2.2637-39
- RHEL-186655 CVE-2026-47162 vim: netrw code injection via
NetrwBookHistSave()
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:8.2.2637-38
- RHEL-192114 CVE-2026-57456 vim: possible code execution with python
complete