Apr 8, 2026·6 min read·4 visits
Vim < 9.2.0074 contains an out-of-bounds read (CWE-125) in src/tag.c triggered by malformed Emacs tags files. Exploitation requires user interaction and causes denial of service.
Vim versions prior to 9.2.0074 suffer from an out-of-bounds read vulnerability in the Emacs-style tags file parsing logic. The flaw allows an attacker to trigger an out-of-bounds memory read of up to 7 bytes by supplying a crafted tags file. Processing this file via standard Vim commands results in a denial of service (crash) or potential minor heap memory exposure.
Vim versions prior to 9.2.0074 contain a memory safety vulnerability within the tags file parsing subsystem. The flaw specifically resides in the logic responsible for processing Emacs-style tags files. This component parses metadata to enable code navigation features.
The vulnerability is classified as an out-of-bounds read (CWE-125) and heap-based buffer overflow (CWE-122). When Vim encounters a malformed tags file, the parsing loop fails to correctly enforce memory boundaries on the heap-allocated buffer. This allows the application to read adjacent heap memory during the execution of standard tag lookup commands.
Exploitation requires a user to manually configure Vim to use a malicious tags file or to execute a tag command within a directory containing the file. Successful triggering of the flaw primarily results in an application crash, establishing a localized denial of service condition.
The vulnerability originates in the emacs_tags_new_filename() function located within src/tag.c. This function is invoked when Vim detects an Emacs-style format within the active tags file. Vim allocates a fixed-size heap buffer, referenced as st->ebuf, which typically holds 512 bytes of line data.
During normal operation, the parser searches the buffer for a comma character (,). This comma acts as a structural delimiter separating the filename from the subsequent tags metadata. The for loop responsible for locating this delimiter increments a pointer p across the buffer contents.
The logic failure occurs because the loop termination condition only checks for the presence of the comma or a non-null character. If an attacker provides a line exceeding the 512-byte buffer length without including a comma, the pointer p increments until it reaches the NUL byte at the end of the buffer.
Because the parsing function lacks a validation step to verify why the loop terminated, it incorrectly assumes a valid string position. The subsequent code block processes the memory address pointed to by p, leading to an out-of-bounds read of up to 7 bytes as the function attempts to identify a secondary include directive.
The vulnerable implementation relies on an unsafe loop construct that implicitly assumes the presence of a delimiter or valid string termination within bounds. The pointer p is initialized to the start of the heap buffer and incremented sequentially.
for (p = st->ebuf; *p && *p != ','; p++)
;
*p = NUL;In this vulnerable state, if the pointer reaches the null terminator at the end of st->ebuf, the loop exits. The immediate write operation *p = NUL overrides the existing null byte, but subsequent instructions advance the pointer beyond the allocated buffer space.
The patch introduced in commit f6a7f469a9c0d09e84cd6cb46c3a9e76f684da2d mitigates this flaw by explicitly validating the state of the pointer after the loop terminates.
--- a/src/tag.c
+++ b/src/tag.c
@@ -1901,6 +1901,9 @@ emacs_tags_new_filename(findtags_state_T *st)
for (p = st->ebuf; *p && *p != ','; p++)
;
+ // invalid
+ if (*p == NUL)
+ return;
*p = NUL;By adding the if (*p == NUL) return; condition, Vim ensures that parsing halts immediately if the delimiter is absent and the end of the string is reached. This effectively contains the pointer within the boundaries of st->ebuf.
Exploitation relies on the distribution of a malicious tags file and subsequent user interaction. The attacker must format the file to trigger the specific parsing logic within emacs_tags_new_filename(). The file must begin with a form-feed character (\x0c) to instruct Vim to parse it as an Emacs-style tags file.
Following the form-feed character, the attacker provides a continuous string of characters exceeding the 512-byte buffer capacity. This string must deliberately omit the comma character expected by the parser. A standard proof-of-concept constructs a payload containing 515 consecutive 'a' characters.
" PoC to trigger the out-of-bounds read
func Test_evil_emacs_tagfile()
CheckFeature emacs_tags
let longline = repeat('a', 515)
call writefile([
\ "\x0c",
\ longline
\ ], 'Xtags', 'D')
set tags=Xtags
call assert_fails(':tag a', 'E426:')
set tags&
endfuncWhen a user executes a tag navigation command such as :tag a, Vim reads the constructed file. The parser processes the overlong line, pointer p exceeds the buffer boundary, and the application attempts to read adjacent heap memory. This invariably leads to a segmentation fault on modern operating systems due to memory access violations.
The primary consequence of this vulnerability is an application crash. The out-of-bounds read triggers a memory access violation, causing the operating system to terminate the Vim process. This constitutes a localized denial of service.
The confidentiality impact is restricted by the exact behavior of the out-of-bounds read. The vulnerability permits reading a maximum of 7 bytes beyond the st->ebuf allocation. Under highly specific heap layouts, these bytes might contain sensitive data from adjacent allocations, though extracting this data to a readable output stream is highly complex and impractical in standard usage.
The CVSS v3.1 base score of 4.4 reflects the strict prerequisites for exploitation. The attack vector is classified as Local (AV:L), as the attacker cannot trigger the flaw across a network interface. User interaction is strictly required (UI:R), as the victim must actively invoke a tags-related command against the malicious file.
The Exploit Prediction Scoring System (EPSS) indicates a negligible probability of exploitation in the wild, with a score of 0.00004. This correlates with the lack of known weaponization or ransomware associations. The vulnerability represents a minimal risk to enterprise environments unless untrusted source code repositories are routinely navigated using legacy Vim features.
The comprehensive resolution for this vulnerability requires updating Vim to version 9.2.0074 or a subsequent release. Operating system vendors and package maintainers incorporate this upstream patch into their respective distribution channels. Security engineers should verify the deployment of the updated binary across developer workstations and shared development servers.
In environments where immediate binary updates are unfeasible, administrators can mitigate the risk by restricting tag file usage. Users should be instructed to avoid executing :tag commands within untrusted repositories or directories obtained from external sources.
Disabling Emacs-style tags support during the compilation of Vim entirely removes the vulnerable code path. However, this approach requires rebuilding the application from source and may disrupt workflows dependent on this specific formatting standard.
Detection mechanisms should focus on identifying outdated Vim installations rather than intercepting exploit attempts. The execution occurs entirely within the local user context, making network-based detection systems ineffective. System administrators can monitor crash logs for segmentation faults originating from the vim process during file parsing operations.
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Vim Vim | < 9.2.0074 | 9.2.0074 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-125 |
| Attack Vector | Local |
| CVSS Score | 4.4 |
| EPSS Score | 0.00004 |
| Exploit Status | PoC Available |
| CISA KEV | Not Listed |
The software reads data past the end, or before the beginning, of the intended buffer.