[Security] MacVim affected by GHSA-crm5-rh6j-2c7c — netrw NetrwBookHistSave() code injection via crafted directory name (vim < 9.2.0495)
Summary
MacVim bundles the vim runtime at version 9.2 (patches 1-321 in the current build), which is
below the patched version 9.2.0495 that fixes a code injection vulnerability in the netrw
plugin's s:NetrwBookHistSave() function.
Vulnerability Details
- GHSA: GHSA-crm5-rh6j-2c7c
- Upstream fix: vim 9.2.0495 (commit
f08ab2f4d7d2947c8dd6c179ae08ee6146a2694b)
- Affected code:
runtime/pack/dist/opt/netrw/autoload/netrw.vim — s:NetrwBookHistSave()
- Vulnerability type: CWE-94 — Improper Control of Generation of Code (Code Injection)
Root Cause
In s:NetrwBookHistSave(), the directory history is serialized to ~/.vim/.netrwhist using
a single-quoted Vimscript string literal without escaping embedded single quotes:
" runtime/pack/dist/opt/netrw/autoload/netrw.vim line 2961 (macvim r183)
call setline(lastline,'let g:netrw_dirhist_'.cnt."='".g:netrw_dirhist_{cnt}."'")
This generates lines of the form:
let g:netrw_dirhist_1='/some/path'
If the directory name (stored in g:netrw_dirhist_{cnt}) contains a single quote ', the
generated Vimscript breaks out of the string literal. For example, a directory named:
x'|let g:injected=1|let y='z
would generate:
let g:netrw_dirhist_1='x'|let g:injected=1|let y='z'
When ~/.vim/.netrwhist is later sourced by netrw (at vim startup via the VimLeave
autocommand that calls NetrwBookHistRead), the injected Vimscript executes.
Attack Scenario
- An attacker creates a directory named with an embedded single-quote followed by
Vimscript commands:
mkdir -p "target/x'|call system('id > /tmp/pwned')|let y='z"
- The victim opens this directory in netrw (
:Explore) inside MacVim and then quits vim.
s:NetrwBookHistSave() writes the crafted path to ~/.vim/.netrwhist unescaped.
- The next time MacVim starts and opens netrw,
NetrwBookHistRead() sources .netrwhist,
executing the injected call system('id > /tmp/pwned') command.
This provides persistent arbitrary command execution — the payload is written once and
fires on every subsequent vim startup.
Affected MacVim Code
" netrw.vim line 2961 (macvim r183)
call setline(lastline,'let g:netrw_dirhist_'.cnt."='".g:netrw_dirhist_{cnt}."'")
The directory path g:netrw_dirhist_{cnt} is interpolated directly into a single-quoted
string without any escaping.
Affected MacVim Version
MacVim r183 (vim 9.2 patches 1-321) — current HEAD as of 2026-05-18.
The fix commit f08ab2f4d7d2947c8dd6c179ae08ee6146a2694b from vim/vim is not present
in the macvim-dev/macvim repository.
Suggested Fix
Merge or cherry-pick vim/vim patches up to at least 9.2.0495.
The fix replaces the unescaped string interpolation with Vimscript's built-in string()
function, which properly double-quotes the value and escapes embedded single quotes:
" Fixed (vim 9.2.0495):
call setline(lastline,'let g:netrw_dirhist_'.cnt.'='.string(g:netrw_dirhist_{cnt}))
string() produces a safely quoted Vimscript literal (e.g., "x'|cmd" for a path
containing '), so the value round-trips safely through source.
References
[Security] MacVim affected by GHSA-crm5-rh6j-2c7c — netrw NetrwBookHistSave() code injection via crafted directory name (vim < 9.2.0495)
Summary
MacVim bundles the vim runtime at version 9.2 (patches 1-321 in the current build), which is
below the patched version 9.2.0495 that fixes a code injection vulnerability in the netrw
plugin's
s:NetrwBookHistSave()function.Vulnerability Details
f08ab2f4d7d2947c8dd6c179ae08ee6146a2694b)runtime/pack/dist/opt/netrw/autoload/netrw.vim—s:NetrwBookHistSave()Root Cause
In
s:NetrwBookHistSave(), the directory history is serialized to~/.vim/.netrwhistusinga single-quoted Vimscript string literal without escaping embedded single quotes:
This generates lines of the form:
If the directory name (stored in
g:netrw_dirhist_{cnt}) contains a single quote', thegenerated Vimscript breaks out of the string literal. For example, a directory named:
would generate:
When
~/.vim/.netrwhistis later sourced by netrw (at vim startup via theVimLeaveautocommand that calls
NetrwBookHistRead), the injected Vimscript executes.Attack Scenario
Vimscript commands:
mkdir -p "target/x'|call system('id > /tmp/pwned')|let y='z":Explore) inside MacVim and then quits vim.s:NetrwBookHistSave()writes the crafted path to~/.vim/.netrwhistunescaped.NetrwBookHistRead()sources.netrwhist,executing the injected
call system('id > /tmp/pwned')command.This provides persistent arbitrary command execution — the payload is written once and
fires on every subsequent vim startup.
Affected MacVim Code
The directory path
g:netrw_dirhist_{cnt}is interpolated directly into a single-quotedstring without any escaping.
Affected MacVim Version
MacVim r183 (vim 9.2 patches 1-321) — current HEAD as of 2026-05-18.
The fix commit
f08ab2f4d7d2947c8dd6c179ae08ee6146a2694bfromvim/vimis not presentin the
macvim-dev/macvimrepository.Suggested Fix
Merge or cherry-pick
vim/vimpatches up to at least 9.2.0495.The fix replaces the unescaped string interpolation with Vimscript's built-in
string()function, which properly double-quotes the value and escapes embedded single quotes:
string()produces a safely quoted Vimscript literal (e.g.,"x'|cmd"for a pathcontaining
'), so the value round-trips safely throughsource.References