GitHub Advisoryadvisory · NuGet
GHSA-xw6w-9jjh-p9cr Scriban has Multiple Denial-of-Service Vectors via Unbounded Resource Consumption During Expression Evaluation
MEDIUM
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