macvim-dev / macvim-dev/macvim
[Security] MacVim affected by GHSA-crm5-rh6j-2c7c — netrw NetrwBookHistSave() code injection via crafted directory name (vim < 9.2.0495)
まだ誰も着手していません。
- 主要言語
- Vim Script
- スター
- 7.9k
- フォーク
- 691
- PR マージ指標
- 30日以内にマージされた PR はありません
説明
[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/.netrwhistunescaped.- The next time MacVim starts and opens netrw,
NetrwBookHistRead()sources.netrwhist,
executing the injectedcall 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
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
runtime/pack/dist/opt/netrw/autoload/netrw.vim の s:NetrwBookHistSave() から始め、upstream の Vim コミット f08ab2f4d7d2947c8dd6c179ae08ee6146a2694b と比較します。バンドルされている runtime を更新し、その後 MacVim をビルドして、単一引用符を含むディレクトリ名が、注入された Vimscript を実行せずに安全に永続化されることを確認します。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- vim
- 領域
- security
- issue の種類
- バグ
- 難易度
- 2/5
- 見積もり時間
- 半日
- 活発さ
- 静か
- 明瞭さ
- 明確に書かれている
- 初心者へのやさしさ
- 72/100