GitHub Advisoryadvisory · NuGet

GHSA-xw6w-9jjh-p9cr Scriban has Multiple Denial-of-Service Vectors via Unbounded Resource Consumption During Expression Evaluation

MEDIUM Published 2026-03-24 Modified 2026-07-06 Official page ↗
Ecosystem
NuGet
Packages
Scriban, Scriban.Signed
Severity
Moderate
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
Weaknesses
CWE-400
Reviewed
2026-03-24

Affected packages

• NuGet Scriban: < 7.0.0 → fixed in 7.0.0 • NuGet Scriban.Signed: < 7.0.0 → fixed in 7.0.0

Description

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: ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs:319-334 var leftText = context.ObjectToString(left); var builder = new StringBuilder(); for (int i = 0; i ` iterators: ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs:401-417 private static IEnumerable RangeInclude(BigInteger left, BigInteger right) { if (left ().Count()`, fully enumerating the range • `ArrayFunctions.Join` (line 388) iterates with `foreach` and appends to a `StringBuilder` with no size limit PoC Vector 1 — String multiplication OOM: ```csharp var template = Template.Parse("{{ 'AAAA' * 500000000 }}"); var context = new TemplateContext(); // context.LimitToString is 1048576 by default — does NOT protect this path template.Render(context); // OutOfMemoryException: attempts ~2GB allocation ``` Vector 2 — BigInteger shift OOM: ```csharp var template = Template.Parse("{{ 1 0 && (long)value * leftText.Length > context.LimitToString) { throw new ScriptRuntimeException(span, $"String multiplication would exceed LimitToString ({context.LimitToString} characters)"); } var builder = new StringBuilder(); for (int i = 0; i 1048576) // Same as MaxBigInteger bit count throw new ScriptRuntimeException(span, $"Shift amount {right} exceeds maximum allowed (1048576)"); return (BigInteger)left RangeInclude(TemplateContext context, BigInteger left, BigInteger right) { var maxRange = context.LoopLimit > 0 ? context.LoopLimit : int.MaxValue; int count = 0; if (left maxRange) throw new ScriptRuntimeException(context.CurrentNode.Span, $"Range enumeration exceeds LoopLimit ({maxRange})"); yield return FitToBestInteger(i); } } // ... same for descending branch } ``` Alternatively, validate range size eagerly at creation time: `if (BigInteger.Abs(right - left) > maxRange) throw ...`

Related

Weakness · CWE (1)

  • CWE-400 Uncontrolled Resource Consumption weakness

References