Prevent stack overflow from deeply nested sections - #96
Merged
cbroglie merged 1 commit intoAug 27, 2026
Merged
Conversation
parseSection recurses once per open section tag, so a template consisting
of a large number of section openers (for example many "{{#a}}") drives the
parser to recurse until the goroutine stack is exhausted. Go reports this as
an unrecoverable "fatal error: stack overflow" that aborts the whole process
and cannot be caught with recover(), so any code that parses untrusted
templates via ParseString/Render can be crashed by a single crafted string.
Bound the section nesting depth and return an ordinary parse error once it is
exceeded. The limit (10000) is far above anything a real template needs, so
well-formed templates are unaffected.
Owner
|
Thanks @ChrisJr404! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Parsing a template recurses once per open section tag:
parseSectioncalls itself for every{{#...}}/{{^...}}it encounters. There is no bound on that recursion, so a template made up of a large number of section openers drives the parser to recurse until the goroutine stack is exhausted.When that happens Go aborts with
fatal error: stack overflow, which is not a normalpanicand cannot be caught withrecover()— it takes down the whole process. Any program that parses untrusted templates through the documented entry points (ParseString,Render, and friends) can therefore be crashed by a single crafted string.Minimal reproducer:
Fix
Thread a depth counter through
parseSectionand return an ordinary parse error (ErrNestingTooDeep) once the nesting exceeds a generous limit (10000). Real templates never approach that depth, so well-formed input — including deeply-but-reasonably nested sections — is unaffected, while a hostile template now yields a normal error instead of crashing the process.Added tests cover both sides: excessive nesting now returns
ErrNestingTooDeep, and ordinary nested (properly closed) sections still parse. The full suite, including the upstream mustache spec conformance tests, passes.