encode: bound nesting depth to prevent stack overflow on deep input#79
Open
martinholovsky wants to merge 1 commit into
Open
encode: bound nesting depth to prevent stack overflow on deep input#79martinholovsky wants to merge 1 commit into
martinholovsky wants to merge 1 commit into
Conversation
The decoder gained a maxNestingDepth guard to fix a stack-exhaustion issue (GHSA-5wfc-hjrc-gq87 / GO-2026-5157), but the encoder was left unguarded. Its only depth-related logic is cycle detection, which triggers solely on a repeated pointer; a deeply nested, non-cyclic value (distinct pointer at every level) slips past it, so hjson.Marshal recurses until the goroutine stack overflows — a fatal, unrecoverable crash (DoS). Reuse the existing pDepth counter to also enforce maxNestingDepth on the encode side, returning the same "Exceeded max depth" error the decoder already returns. No behavior change for normal input (nothing legitimately nests 10000 deep). Reproduce (pre-fix): var v any = "x"; for i := 0; i < 3_000_000; i++ { v = []any{v} }; hjson.Marshal(v) -> fatal error: stack overflow.
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.
The decoder gained a
maxNestingDepthguard to fix a stack-exhaustion issue (GHSA-5wfc-hjrc-gq87 / GO-2026-5157), but the encoder was left unguarded.The encoder’s only depth-related logic is cycle detection, which triggers solely on a repeated pointer:
A deeply nested, non-cyclic value has a distinct pointer at every level, so the cycle check never fires and
hjson.Marshalrecurses until the goroutine stack overflows — a fatal, unrecoverable crash (a Go stack overflow cannot berecover()-ed).Reproduce (still applies to v4.6.0):
Fix: reuse the existing
pDepthcounter to also enforcemaxNestingDepthon the encode side, returning the same"Exceeded max depth (%d)"error the decoder already returns. No behavior change for normal input (nothing legitimately nests 10000 deep); the cycle check still catches true cycles early. Added a regression test (TestEncodeMaxDepth).go test ./...passes;gofmtclean.