Vim received a security patch on February 27, 2026 that fixes a stack-based buffer overflow in the statusline renderer: a flaw in build_stl_str_hl() could allow a large multi‑byte fill character to write past a fixed 4096‑byte stack buffer when a terminal is extremely wide, and the issue is addressed in patch level 9.2.0078. (github.com)
Vim is a ubiquitous, long‑lived command‑line text editor used across workstations, servers, container images, and build systems. Its statusline — the small line at the bottom of each window showing file name, mode, position and custom widgets — is highly configurable. Users and plugins can set the statusline format and the characters used to fill gaps (the fillchars and related options), and Vim constructs the visible string into an internal buffer before drawing it to the terminal.
The code that assembles the statusline uses a fixed stack buffer defined as
Detection and inventory steps:
Acknowledgment: The vulnerability, patch, and advisory details are recorded in the upstream GitHub advisory and commit, and the issue was cataloged in public vulnerability feeds and NVD under CVE‑2026‑28422. (github.com)
Source: MSRC Security Update Guide - Microsoft Security Response Center
Background
Vim is a ubiquitous, long‑lived command‑line text editor used across workstations, servers, container images, and build systems. Its statusline — the small line at the bottom of each window showing file name, mode, position and custom widgets — is highly configurable. Users and plugins can set the statusline format and the characters used to fill gaps (the fillchars and related options), and Vim constructs the visible string into an internal buffer before drawing it to the terminal.The code that assembles the statusline uses a fixed stack buffer defined as
MAXPATHL (4096 bytes). When drawing gaps (for example, using the %= alignment and fill characters), Vim previously calculated space based on terminal cell width rather than the number of bytes required to represent multi‑byte (UTF‑8) characters, allowing a mismatch between the checked size and the actual byte footprint written to the stack buffer. This is the root cause fixed by the patch. (github.com)What the vulnerability is (technical summary)
- Vulnerable function: build_stl_str_hl()
- Symptom: stack‑buffer‑overflow in a local stack buffer (
MAXPATHL= 4096) - Trigger: rendering a statusline that uses a multi‑byte fill character on a very wide terminal (tens of hundreds to thousands of columns)
- Effect: writing past the 4096‑byte stack buffer — advisory notes overflow can be up to ~1904 bytes — causing memory corruption that can lead to crashes or unpredictable behavior when the statusline is redrawn. (github.com)
maxwidth, but later the loop that writes fillchar bytes used the byte length of the character, which for many Unicode characters can be two, three, or four bytes in UTF‑8. On sufficiently wide terminals the multiplication of cells × bytes per character exceeded the 4096‑byte limit that had been used for bounds checking, creating an overflow. The upstream fix calculates the expected byte increase using MB_CHAR2LEN(fillchar) and adjusts the check accordingly. (github.com)Timeline and vendor response
- Vulnerability report and PoC: reported by GitHub users (acknowledged as
ehdgks0627andun3xploitable) and disclosed to the Vim maintainers. (github.com) - Patch committed: GitHub commit 4e5b9e3 (patch level 9.2.0078) updates the size check in
build_stl_str_hl()to account for the byte length of the fill character (usingMB_CHAR2LEN). (github.com) - CVE assignment and public listing: CVE‑2026‑28422 was created and recorded in public CVE/NVD datasets; GitHub registered the advisory and NVD incorporated the entry. The public advisory and NVD entry list the issue, the patched version, and the CVSS vector assigned by the Canonical Numbering Authority (CNA). (nvd.nist.gov)
Dissecting the patch (what changed and why it matters)
The commit identifies the exact logic error and applies a precise fix:- Before: the code used
width(screen cells) to decide if there was room in the output buffer. - After: the code multiplies the difference
(maxwidth - width)byMB_CHAR2LEN(fillchar)(the byte length of the fill character) when computing whether adding the fill will exceed the output buffer. This prevents the situation where the code thinks space remains (in cells) while the byte requirement exceedsMAXPATHL.
- outputlen + (maxwidth - width) * MB_CHAR2LEN(fillchar) + 1 < outlen
Exploitability and real‑world impact
Understanding exploitability requires parsing a few environmental factors:- Attack surface: local — the CVSS vector assigns an Attack Vector: Local rating. An attacker must be able to cause a user’s Vim process to construct a statusline using attacker‑controlled
fillcharsorstatuslinecontent. Typical vectors include malicious modelines, crafted plugins, or configuration files that a user opens and which Vim parses. (github.com) - User interaction: required — the user must open a file, load a plugin, or otherwise cause the vulnerable code path to execute. The advisory explicitly notes that user interaction (e.g., opening a file) is necessary in the CVSS scoring. (github.com)
- Complexity: High according to the advisory’s CVSS breakdown. Exploiting stack overflows for code execution depends on platform-specific mitigations (stack canaries, ASLR, non‑executable stacks, compiler hardening). The advisory classifies the overall severity as Low because of these barriers and the restrictions on the attack vector.
- Effect: memory corruption — while immediate RCE is not guaranteed in all contexts, memory corruption can cause crashes, data corruption, or in some environments be leveraged into code execution. An overflow up to ~1904 bytes into the stack can corrupt return addresses, saved registers, or local variables, depending on compiler and ABI. (github.com)
Attack scenarios and threat modelling
Consider three realistic threat scenarios:- Scenario A — Malicious modeline in a file: an attacker crafts a text file with a modeline that sets
statuslineorfillcharsto values that include a multi‑byte character. If a user opens the file and modeline processing is enabled, Vim may process the modeline and create the statusline in the vulnerable way. This path is local but practical against users who routinely open files from untrusted sources. (github.com) - Scenario B — Malicious plugin: a plugin installed from third‑party sources or a repository manipulates global options or statusline configuration. If the plugin is installed or executed by a user or during provisioning, the plugin could force the conditions needed to trigger the overflow. This is especially relevant for automated CI images or container builds that add arbitrary community plugins. (github.com)
- Scenario C — Supply‑chain contamination: a distribution, package mirror, or build recipe that bundles an unpatched Vim exposes every system that uses that package. This is a typical supply‑chain risk: an unpatched binary or package propagates the vulnerability at scale. Timely distribution updates are therefore essential. (nvd.nist.gov)
Detection, hunting, and inventory
Operational response should combine discovery and hardening.Detection and inventory steps:
- Inventory Vim versions: identify installed Vim binaries and packages and record their version/patch level. Any build or package with a patch level earlier than 9.2.0078 should be treated as vulnerable. Use your package manager or
vim --versionoutput to enumerate included patch numbers. (github.com) - Search for occurrences of
modelineusage or enabling ofmodeline/modelines: systems that enable modelines are higher risk. Find repositories and dotfiles that setset modelineorset modelines=to non‑zero. Search developer home directories and configuration management templates. - Audit plugin installation paths: look for third‑party plugin deployments in user directories and system‑wide locations. Pay attention to CI images and container definitions that may pull community plugins.
- Monitor crashes and core dumps: a sudden increase in Vim crashes (especially during statusline redraws) in logs, X sessions, or automated builds can indicate attempts to trigger the overflow.
- Threat hunting queries: scan configuration repositories and dotfiles for unusual
fillcharsentries that include multi‑byte characters, or statusline strings crafted to include wide characters.
Immediate mitigations (if you cannot patch immediately)
If upgrading to patched Vim (9.2.0078) is not immediately possible, apply mitigations to reduce exposure:- Disable modelines entirely: set
set nomodelinein global/etc/vim/vimrcor user~/.vimrc. Modelines are a frequent attack vector for local configuration injection. This prevents attacker‑controlled modeline directives in files from being parsed. (Be deliberate: modeline is a convenience feature; disabling it is a practical security tradeoff.) (github.com) - Limit plugin sources: temporarily restrict plugin installation to vetted repos; avoid running
:PlugInstallor equivalent for untrusted plugins; audit existing plugins for code that manipulatesstatuslineorfillchars. (github.com) - Avoid multi‑byte fill characters in statusline/fillchars options: ensure
fillcharsandstatuslineuse single‑byte ASCII characters where feasible, or disable any custom statusline scripts that insert multi‑byte separators. - Constrain terminal width where practical: while not always feasible, limiting terminal width to values that keep the multiplication (columns × bytes per char) under 4096 prevents the condition. The advisory suggests the overflow becomes relevant at very wide terminals (the advisory gives a ~1365 column threshold for a 3‑byte fill char). This is a brittle and environment‑dependent mitigation and should be used only as an emergency measure until patching is possible. (github.com)
- Harden processes: ensure distributions compile Vim with stack protection (stack canaries), enable ASLR system‑wide, and apply compiler hardening flags in your build pipeline. While not a replacement for the patch, these measures raise exploitation difficulty. (github.com)
Patch and deployment advice
- Apply the upstream patch by upgrading to Vim 9.2.0078 or a downstream package that includes that patch. The GitHub release and commit are the authoritative upstream artifacts. (github.com)
- Coordinate with distribution/package maintainers: if you manage system images in enterprise fleets or container registries, rebuild images with the patched Vim and push updates through your CI to avoid leaving outdated images in circulation. Confirm the package change by checking the included patch number or commit hash.
- Test: after patching, run regression tests that exercise statusline rendering, including wide terminals and multi‑byte characters, to validate there is no regression in behavior for legitimate configurations. The upstream patch is targeted; however, testing is standard operational hygiene.
- Communicate: notify developers and users about the change, remind them of the risks of enabling modelines and installing unvetted plugins, and provide guidance for verifying their local Vim instance has the patch. (github.com)
Why this class of bug keeps appearing (analysis)
Stack‑buffer overflows in C projects remain a recurring problem because:- Fixed‑size buffers are common and cheap: developers frequently use fixed stack arrays for convenience and performance without always reconciling display metrics (cells) with encoding metrics (bytes). The mismatch between visual cell width and byte length for multi‑byte Unicode is conceptually subtle and easy to get wrong when code deals concurrently with display layout and raw bytes.
- Unicode complexity: modern software must handle variable‑width encodings and grapheme clusters. Mistakes that mix units (cells vs bytes vs codepoints) introduce off‑by‑one and multiplication errors that only appear with certain character choices, encodings, or unusually large terminal sizes.
- Legacy codebase: projects with decades of history (Vim originated in the 1990s) have many codepaths written before UTF‑8 and wide‑character terminals were mainstream, increasing the chance of surprising interactions when features evolve.
- Plugin/modeline ecosystem: adding features that accept configuration from files/plugins increases attack surface. Presenting a desirable convenience (rich statuslines, icons, separators) to users invites extensions that can also become weapons when combined with parsing bugs.
Practical checklist for teams (step‑by‑step)
- Inventory: list all systems (workstations, servers, containers) that ship or build with Vim and record the patch level.
- Prioritize: identify systems that open untrusted files or run developer tools where users might open third‑party content.
- Patch: upgrade Vim to 9.2.0078 or apply an upstream backport. Validate the installed binary shows the new patch level. (github.com)
- Mitigate temporarily: disable modelines, restrict plugin sources, avoid multi‑byte fillchars until patched. (github.com)
- Monitor: scan logs for recent Vim crashes and run the hunting queries described above.
- Communicate: brief developers about modeline best practices and plugin hygiene.
- Harden builds: ensure compiled packages use modern hardening flags and system features (ASLR, stack canaries) to raise exploitation difficulty.
- Re‑audit: after patching, run regression tests focusing on statusline rendering in wide terminals and with multi‑byte characters. (github.com)
Longer‑term lessons and recommendations
- Treat display‑level logic and byte‑level logic as separate domains: always convert display cell counts into byte counts before allocating or validating buffers.
- Reduce implicit trust in configuration from files: modelines and similar conveniences should be disabled by default in hardened environments or require explicit user consent to be run.
- Encourage minimal, well‑scoped patches: the upstream fix here is a targeted check that resolves the immediate condition; similar surgical fixes should be preferred where safe.
- Improve automated testing: introduce fuzzing or targeted test cases that exercise combinations of terminal width, multi‑byte fill characters, and statusline templates to catch such mismatches earlier.
- Maintain package‑level alerts: distributions and CI pipelines must flag new upstream security advisories automatically so that images and packages are rebuilt quickly.
Final assessment
CVE‑2026‑28422 is a concrete example of how unit mismatches (cells vs bytes) in UI rendering code can lead to stack memory corruption. The vulnerability is notable because:- It affects a widely used tool — Vim — that is present in many developer and production environments. (github.com)
- The fix is small and available in a new patch level (9.2.0078), so remediation is straightforward for most operators. (github.com)
- Exploitation is constrained by locality and required user interaction, which reduces systemic risk; however, the ability to trigger memory corruption via modelines or plugins means that attackers with filesystem access or social‑engineering vectors can create practical attack paths. (github.com)
Acknowledgment: The vulnerability, patch, and advisory details are recorded in the upstream GitHub advisory and commit, and the issue was cataloged in public vulnerability feeds and NVD under CVE‑2026‑28422. (github.com)
Source: MSRC Security Update Guide - Microsoft Security Response Center