The vulnerability is due to unrestricted AST node creation during parsing, leading to memory exhaustion. The patch (commit 0d19441454426d2f58edb22c31f3ba5f99c7a26e) introduces a node budget (MaxNodes in conf.Config) and modifies the parser to check this budget during node creation.
The core changes are in parser/parser.go:
nodeCount field was added to the parser struct.checkNodeLimit, createNode, and createMemberNode were added to the parser struct. These methods increment nodeCount and check against config.MaxNodes.parseExpression, parsePrimary, parseCall, parseMapExpression, etc.) were modified. Previously, they created AST nodes directly (e.g., &NodeType{...}). After the patch, they now call p.createNode(...) or p.createMemberNode(...) which incorporate the limit check.Therefore, all these parse* methods within parser/parser.go that were changed to use the new node creation wrappers were the functions that, before the patch, would have created AST nodes without any limits, directly contributing to the memory exhaustion vulnerability when processing a large input string. The top-level functions Parse and ParseWithConfig are the entry points that initiate this vulnerable parsing process.
| Package Name | Ecosystem | Vulnerable Versions | First Patched Version |
|---|---|---|---|
| github.com/expr-lang/expr | go | < 1.17.0 | 1.17.0 |
Ongoing coverage of React2Shell