From 42f9ee904caf6681ee32e7b048f15ab7cddf3eb3 Mon Sep 17 00:00:00 2001 From: Ville Vesilehto Date: Wed, 14 May 2025 18:16:54 +0000 Subject: text/template: limit expression parenthesis nesting Deeply nested parenthesized expressions could cause a stack overflow during parsing. This change introduces a depth limit (maxStackDepth) tracked in Tree.stackDepth to prevent this. Additionally, this commit clarifies the security model in the package documentation, noting that template authors are trusted as text/template does not auto-escape. Fixes #71201 Change-Id: Iab2c2ea6c193ceb44bb2bc7554f3fccf99a9542f GitHub-Last-Rev: f4ebd1719ff966ae3c6516e3fb935dfea2f5362e GitHub-Pull-Request: golang/go#73670 Reviewed-on: https://go-review.googlesource.com/c/go/+/671755 Reviewed-by: Roland Shoemaker Reviewed-by: Michael Knyszek Auto-Submit: Sean Liao LUCI-TryBot-Result: Go LUCI Reviewed-by: Rob Pike --- src/text/template/parse/parse_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/text/template/parse/parse_test.go') diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go index 26aff330fe..e8e6fe9759 100644 --- a/src/text/template/parse/parse_test.go +++ b/src/text/template/parse/parse_test.go @@ -86,6 +86,11 @@ var numberTests = []numberTest{ {"0xef", true, true, true, false, 0xef, 0xef, 0xef, 0}, } +func init() { + // Use a small stack limit for testing to avoid creating huge expressions. + maxStackDepth = 3 +} + func TestNumberParse(t *testing.T) { for _, test := range numberTests { // If fmt.Sscan thinks it's complex, it's complex. We can't trust the output @@ -327,6 +332,15 @@ var parseTests = []parseTest{ {"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""}, // Missing pipeline in block {"block definition", `{{block "foo"}}hello{{end}}`, hasError, ""}, + + // Expression nested depth tests. + {"paren nesting normal", "{{ (( 1 )) }}", noError, "{{((1))}}"}, + {"paren nesting at limit", "{{ ((( 1 ))) }}", noError, "{{(((1)))}}"}, + {"paren nesting exceeds limit", "{{ (((( 1 )))) }}", hasError, "template: test:1: max expression depth exceeded"}, + {"paren nesting in pipeline", "{{ ((( 1 ))) | printf }}", noError, "{{(((1))) | printf}}"}, + {"paren nesting in pipeline exceeds limit", "{{ (((( 1 )))) | printf }}", hasError, "template: test:1: max expression depth exceeded"}, + {"paren nesting with other constructs", "{{ if ((( true ))) }}YES{{ end }}", noError, "{{if (((true)))}}\"YES\"{{end}}"}, + {"paren nesting with other constructs exceeds limit", "{{ if (((( true )))) }}YES{{ end }}", hasError, "template: test:1: max expression depth exceeded"}, } var builtins = map[string]any{ -- cgit v1.3-5-g9baa