Commit: patch 9.2.0276: [security]: modeline security bypass

3 views
Skip to first unread message

Christian Brabandt

unread,
Mar 31, 2026, 2:47:14 PM (22 hours ago) Mar 31
to vim...@googlegroups.com
patch 9.2.0276: [security]: modeline security bypass

Commit: https://github.com/vim/vim/commit/75661a66a1db1e1f3f1245c615f13a7de44c0587
Author: Christian Brabandt <c...@256bit.org>
Date: Tue Mar 31 18:29:00 2026 +0000

patch 9.2.0276: [security]: modeline security bypass

Problem: [security]: modeline security bypass
Solution: disallow mapset() from secure mode, set the P_MLE flag for the
'complete', 'guitabtooltip' and 'printheader' options.

Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-8h6p-m6gr-mpw9

Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/map.c b/src/map.c
index 0a909fb93..5f07ef4a8 100644
--- a/src/map.c
+++ b/src/map.c
@@ -2746,6 +2746,9 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED)
int dict_only;
mapblock_T *mp_result[2] = {NULL, NULL};

+ if (check_secure())
+ return;
+
// If first arg is a dict, then that's the only arg permitted.
dict_only = argvars[0].v_type == VAR_DICT;
if (in_vim9script()
diff --git a/src/optiondefs.h b/src/optiondefs.h
index ca2795a36..a6f838308 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -681,7 +681,7 @@ static struct vimoption options[] =
{"compatible", "cp", P_BOOL|P_RALL,
(char_u *)&p_cp, PV_NONE, did_set_compatible, NULL,
{(char_u *)TRUE, (char_u *)FALSE} SCTX_INIT},
- {"complete", "cpt", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ {"complete", "cpt", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP|P_MLE,
(char_u *)&p_cpt, PV_CPT, did_set_complete, expand_set_complete,
{(char_u *)".,w,b,u,t,i", (char_u *)0L}
SCTX_INIT},
@@ -1324,7 +1324,7 @@ static struct vimoption options[] =
{(char_u *)NULL, (char_u *)0L}
#endif
SCTX_INIT},
- {"guitabtooltip", "gtt", P_STRING|P_VI_DEF|P_RWIN,
+ {"guitabtooltip", "gtt", P_STRING|P_VI_DEF|P_RWIN|P_MLE,
#if defined(FEAT_GUI_TABLINE)
(char_u *)&p_gtt, PV_NONE, NULL, NULL,
{(char_u *)"", (char_u *)0L}
@@ -2041,7 +2041,7 @@ static struct vimoption options[] =
{(char_u *)NULL, (char_u *)0L}
#endif
SCTX_INIT},
- {"printheader", "pheader", P_STRING|P_VI_DEF|P_GETTEXT,
+ {"printheader", "pheader", P_STRING|P_VI_DEF|P_GETTEXT|P_MLE,
#ifdef FEAT_PRINTER
(char_u *)&p_header, PV_NONE, NULL, NULL,
// untranslated to avoid problems when 'encoding'
diff --git a/src/testdir/test_modeline.vim b/src/testdir/test_modeline.vim
index 4cc091b9c..25ca6fb43 100644
--- a/src/testdir/test_modeline.vim
+++ b/src/testdir/test_modeline.vim
@@ -490,4 +490,29 @@ func Test_modeline_nowrap_lcs_extends()
set equalalways&
endfunc

+func Test_modeline_forbidden()
+ let tempfile = tempname()
+ let lines =<< trim END
+ some test text for completion
+ vim: set complete=F{->system('touch_should_not_run')} :
+ END
+ call writefile(lines, tempfile, 'D')
+ call assert_fails($'new {tempfile}', 'E992:')
+ bw!
+ let lines =<< trim END
+ some text
+ vim: set guitabtooltip=%{%mapset()%}:
+ END
+ call writefile(lines, tempfile)
+ call assert_fails($'new {tempfile}', 'E992:')
+ bw!
+ let lines =<< trim END
+ some text
+ vim: set printheader=%{mapset('n',0,{})%)%}:
+ END
+ call writefile(lines, tempfile, 'D')
+ call assert_fails($'new {tempfile}', 'E992:')
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 3fa39ae40..708522164 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 276,
/**/
275,
/**/
Reply all
Reply to author
Forward
0 new messages