From c98bf38f69e22d1ab11e56a8ff1ab047cf42adb3 Mon Sep 17 00:00:00 2001 From: valoq Date: Fri, 10 Jul 2026 16:55:30 +0200 Subject: [PATCH] fix: reject unquoted % and $ in set values --- eval_test.go | 18 ++++++++++++++++++ parse.go | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/eval_test.go b/eval_test.go index 4a8c47e14..5694f8190 100644 --- a/eval_test.go +++ b/eval_test.go @@ -661,3 +661,21 @@ func TestApplyLocalBoolOpt(t *testing.T) { } } } + +func TestParseSetValueQuoting(t *testing.T) { + for _, inp := range []string{`set dupfilefmt %f.~%n~`, `setlocal /tmp promptfmt $x`} { + p := newParser(strings.NewReader(inp)) + if p.parse() { + t.Errorf("parse(%q) evaluated %v despite error %v", inp, p.expr, p.err) + } + if p.err == nil { + t.Errorf("parse(%q) expected error", inp) + } + } + for _, inp := range []string{`set dupfilefmt "%f.~%n~"`, `set hidden!`, "set hidden"} { + p := newParser(strings.NewReader(inp)) + if !p.parse() || p.err != nil { + t.Errorf("parse(%q) rejected: %v", inp, p.err) + } + } +} diff --git a/parse.go b/parse.go index 6b274f03f..2b8453a8b 100644 --- a/parse.go +++ b/parse.go @@ -237,6 +237,10 @@ func (p *parser) parseExpr() expr { s.scan() if s.typ != tokenSemicolon { + if s.typ != tokenIdent { + p.err = fmt.Errorf("set %s: unexpected %q, value must be quoted", opt, s.tok) + return nil + } val = s.tok s.scan() } @@ -261,6 +265,10 @@ func (p *parser) parseExpr() expr { s.scan() if s.typ != tokenSemicolon { + if s.typ != tokenIdent { + p.err = fmt.Errorf("setlocal %s: unexpected %q, value must be quoted", opt, s.tok) + return nil + } val = s.tok s.scan() } @@ -410,5 +418,10 @@ func (p *parser) parseExpr() expr { func (p *parser) parse() bool { p.expr = p.parseExpr() + if p.err != nil { + // never evaluate an expression that produced a parse error + p.expr = nil + return false + } return p.expr != nil }