Описание
Scriban has Multiple Denial-of-Service Vectors via Unbounded Resource Consumption During Expression Evaluation
Summary
Scriban's expression evaluation contains three distinct code paths that allow an attacker who can supply a template to cause denial of service through unbounded memory allocation or CPU exhaustion. The existing safety controls (LimitToString, LoopLimit) do not protect these paths, giving applications a false sense of safety when evaluating untrusted templates.
Details
Vector 1: Unbounded string multiplication
In ScriptBinaryExpression.cs, the CalculateToString method handles the string * int operator by looping without any upper bound:
The LimitToString safety control (default 1MB) does not protect this code path. It only applies to ObjectToString output conversions in TemplateContext.Helpers.cs (lines 101-121), not to intermediate string values constructed inside CalculateToString. The LoopLimit also does not apply because this is a C# for loop, not a template-level loop — StepLoop() is never called here.
Vector 2: Unbounded BigInteger shift left
The CalculateLongWithInt and CalculateBigIntegerNoFit methods handle ShiftLeft without any bound on the shift amount:
In contrast, the Power operator at lines 722 and 795 uses BigInteger.ModPow(left, right, MaxBigInteger) to cap results. The MaxBigInteger constant (BigInteger.One << 1024 * 1024, defined at line 690) already exists but is never applied to shift operations.
Vector 3: LoopLimit bypass via range enumeration in builtin functions
The range operators .. and ..< produce lazy IEnumerable<object> iterators:
When these ranges are consumed by builtin functions, LoopLimit is completely bypassed because StepLoop() is only called in ScriptForStatement and ScriptWhileStatement — it is never called in any function under src/Scriban/Functions/. For example:
ArrayFunctions.Size(line 609) calls.Cast<object>().Count(), fully enumerating the rangeArrayFunctions.Join(line 388) iterates withforeachand appends to aStringBuilderwith no size limit
PoC
Vector 1 — String multiplication OOM:
Vector 2 — BigInteger shift OOM:
Vector 3 — LoopLimit bypass via range + builtin:
Impact
An attacker who can supply a Scriban template (common in CMS platforms, email templating systems, reporting tools, and other applications embedding Scriban) can cause denial of service by crashing the host process via OutOfMemoryException or exhausting CPU resources. This is particularly impactful because:
- Applications relying on the default safety controls (
LoopLimit=1000,LimitToString=1MB) believe they are protected against resource exhaustion from untrusted templates, but these controls have gaps. - A single malicious template expression is sufficient — no complex template logic is required.
- The
OutOfMemoryExceptionin vectors 1 and 2 typically terminates the entire process, not just the template evaluation.
Recommended Fix
Vector 1 — String multiplication: Check LimitToString before the loop
Vector 2 — BigInteger shift: Cap the shift amount
Vector 3 — Range + builtins: Add iteration counting to range iterators
Pass TemplateContext to RangeInclude/RangeExclude and enforce a limit:
Alternatively, validate range size eagerly at creation time: if (BigInteger.Abs(right - left) > maxRange) throw ...
Пакеты
Scriban
< 7.0.0
7.0.0
6.5 Medium
CVSS3
Дефекты
6.5 Medium
CVSS3