CVE-2026-47167
Description
A code injection in Vim's cucumber filetype plugin allows arbitrary Ruby execution via crafted step-definition patterns when a user opens a malicious repository.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A code injection in Vim's cucumber filetype plugin allows arbitrary Ruby execution via crafted step-definition patterns when a user opens a malicious repository.
Vulnerability
A code injection vulnerability exists in s:stepmatch() within the cucumber filetype plugin (runtime/ftplugin/cucumber.vim) on Vim builds with +ruby support, prior to version 9.2.0496 [1]. Step-definition patterns read from .rb files under the repository's features/*/ or stories/*/ directories are embedded into a Ruby Kernel.eval argument without sufficient escaping [1]. The #{ guard rejects Ruby string-interpolation sequences but does not prevent the pattern from terminating the regex literal with / and appending arbitrary Ruby statements [1].
Exploitation
An attacker can place a crafted .rb file with a malicious step-definition pattern inside a repository's features/step_definitions/ or stories/ directory [1]. When a victim opens a .feature file in the same repository and invokes a step-jump mapping ([d or ]d), Vim's cucumber filetype plugin processes the step definitions and formats the pattern into a Ruby Kernel.eval call [1]. A pattern such as x/; system("touch marker"); #/ is evaluated by Ruby as a regex literal, a system() call, and a comment, executing the attacker's payload [1]. The attacker does not require any authentication beyond the ability to host a repository that the victim opens in Vim [1].
Impact
Successful exploitation allows the attacker to execute arbitrary Ruby code, and through it arbitrary shell commands, with the privileges of the user running Vim [1]. This can lead to full compromise of the user's system, including data exfiltration, malware installation, or further lateral movement [1]. The impact is limited to Vim builds with +ruby support and when the user opens a malicious repository [1].
Mitigation
The vulnerability has been patched in Vim version 9.2.0496, released on May 26, 2026 [2][3]. The fix replaces the Kernel.eval call with Regexp.new(), which treats the pattern as untrusted data and prevents code injection [2]. Users should update to Vim 9.2.0496 or later [2][3]. As a workaround, users can disable the cucumber filetype plugin by setting filetype plugin indent off or by removing +ruby support from their Vim build [1]. This CVE is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog as of the publication date [1].
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
1a65a52d684bcpatch 9.2.0496: [security]: Code Injection in cucumber filetype plugin
3 files changed · +36 −1
runtime/ftplugin/cucumber.vim+4 −1 modified@@ -2,6 +2,8 @@ " Language: Cucumber " Maintainer: Tim Pope <vimNOSPAM@tpope.org> " Last Change: 2016 Aug 29 +" 2026 May 26 by Vim Project: prevent Code Injection +" https://github.com/vim/vim/security/advisories/GHSA-4473-94jm-w5x9 " Only do this when not done yet for this buffer if (exists("b:did_ftplugin")) @@ -96,7 +98,8 @@ function! s:stepmatch(receiver,target) catch endtry 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}") + " Use Regexp.new, so the pattern stays untrusted data and cannot inject Ruby + ruby VIM.command("return #{if (begin; Regexp.new(VIM.evaluate('pattern')); rescue RegexpError; end) === VIM.evaluate('a:target') then 1 else 0 end}") else return 0 endif
src/testdir/test_filetype.vim+30 −0 modified@@ -3477,4 +3477,34 @@ func Test_app_file() filetype off endfunc +func Test_cucumber_code_injection() + CheckFeature ruby + filetype plugin on + + call mkdir('Xcucu/features/step_definitions', 'pR') + call writefile([ + \ 'Feature: demo', + \ ' Scenario: trigger', + \ ' Given xyzzy', + \ ], 'Xcucu/features/test.feature') + let marker = getcwd() . '/Xcucu/MARKER' + " Malicious step: terminates the regex literal, injects Ruby system(), + " comments the trailing slash. With the fix, the pattern is passed to + " Regexp.new() instead of Kernel.eval() and the payload is inert. + call writefile([ + \ 'Given /xyzzy/; system("touch ' . marker . '"); #/ do', + \ 'end', + \ ], 'Xcucu/features/step_definitions/poc.rb') + + new Xcucu/features/test.feature + call assert_equal('cucumber', &filetype) + call cursor(3, 1) + " Triggers s:jump -> s:steps -> s:stepmatch on every discovered step, + " including the malicious one. Suppress preview and error messages. + silent! normal [d + call assert_false(filereadable(marker), 'Ruby injection executed') + bwipe! + filetype plugin off +endfunc + " vim: shiftwidth=2 sts=2 expandtab
src/version.c+2 −0 modified@@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 496, /**/ 495, /**/
Vulnerability mechanics
Root cause
"The cucumber filetype plugin passes an untrusted step-definition pattern from a .rb file into Ruby's Kernel.eval() without escaping, allowing arbitrary code execution."
Attack vector
An attacker creates a malicious repository containing a Cucumber step-definition `.rb` file under `features/step_definitions/` (or `stories/`) with a crafted pattern that terminates the regex literal and injects arbitrary Ruby code, e.g. `Given /xyzzy/; system("touch ..."); #/ do`. When the victim opens a `.feature` file from that repository and presses `[d` or `]d` to jump to a step definition, Vim's cucumber filetype plugin reads the malicious pattern and passes it to `Kernel.eval()`, executing the injected Ruby and thereby arbitrary shell commands [CWE-94]. No authentication is required beyond opening the repository in Vim.
Affected code
The vulnerability resides in `runtime/ftplugin/cucumber.vim` in the `s:stepmatch()` function. The original code used `Kernel.eval('/'+VIM.evaluate('pattern')+'/')` to construct a Ruby regex from an untrusted step-definition pattern read from `.rb` files under `features/*/` or `stories/*/` directories. The patch replaces this with `Regexp.new(VIM.evaluate('pattern'))` to treat the pattern as data rather than executable code.
What the fix does
The patch replaces `Kernel.eval('/'+VIM.evaluate('pattern')+'/')` with `Regexp.new(VIM.evaluate('pattern'))` in `runtime/ftplugin/cucumber.vim`. The old code interpolated the untrusted pattern directly into a Ruby string that was then evaluated, allowing an attacker to break out of the regex literal and inject arbitrary Ruby. `Regexp.new()` treats its argument as a plain string pattern, so any embedded Ruby code is inert and simply becomes part of the regex syntax, preventing code injection. The test `Test_cucumber_code_injection()` confirms that a malicious pattern no longer executes a `system()` call.
Preconditions
- configVim must be compiled with +ruby support.
- inputThe user must open a .feature file from an attacker-controlled repository.
- inputThe user must invoke the step-jump mapping ([d or ]d).
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.