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: ```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);
AI Analysis
Technical Summary
Scriban's expression evaluation contains three main denial-of-service vectors: (1) unbounded string multiplication where the string is repeated without upper bounds, bypassing LimitToString controls; (2) unbounded BigInteger left shift operations without limits, unlike the Power operator which caps results; (3) bypass of LoopLimit via range enumeration in builtin functions that fully enumerate large ranges without loop count restrictions. These vulnerabilities allow an attacker who can supply a template to cause out-of-memory exceptions or CPU exhaustion, potentially terminating the host process or degrading service availability. The default safety controls do not mitigate these attack vectors, and a single malicious template expression is sufficient to trigger the issue.
Potential Impact
An attacker able to supply Scriban templates can cause denial of service by exhausting memory or CPU resources. The unbounded string multiplication and BigInteger shift can cause out-of-memory exceptions that typically terminate the entire process. The range enumeration bypasses loop limits, allowing CPU exhaustion or large memory allocations during builtin function calls. This impacts applications embedding Scriban for templating, such as CMS platforms, email systems, and reporting tools, especially those relying on default safety controls which are ineffective against these vectors.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. No official fix or patch links are provided in the data. Until a fix is available, applications should avoid evaluating untrusted templates or implement additional custom resource limits around template evaluation. The vendor advisory recommends adding explicit checks for string multiplication size and BigInteger shift bounds, and enforcing loop limits in builtin functions to prevent unbounded resource consumption.
Scriban has Multiple Denial-of-Service Vectors via Unbounded Resource Consumption During Expression Evaluation
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 < 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);
CVSS v3.1
Score 6.5medium
Affected software
Run on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.
Weaknesses
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
Scriban's expression evaluation contains three main denial-of-service vectors: (1) unbounded string multiplication where the string is repeated without upper bounds, bypassing LimitToString controls; (2) unbounded BigInteger left shift operations without limits, unlike the Power operator which caps results; (3) bypass of LoopLimit via range enumeration in builtin functions that fully enumerate large ranges without loop count restrictions. These vulnerabilities allow an attacker who can supply a template to cause out-of-memory exceptions or CPU exhaustion, potentially terminating the host process or degrading service availability. The default safety controls do not mitigate these attack vectors, and a single malicious template expression is sufficient to trigger the issue.
Potential Impact
An attacker able to supply Scriban templates can cause denial of service by exhausting memory or CPU resources. The unbounded string multiplication and BigInteger shift can cause out-of-memory exceptions that typically terminate the entire process. The range enumeration bypasses loop limits, allowing CPU exhaustion or large memory allocations during builtin function calls. This impacts applications embedding Scriban for templating, such as CMS platforms, email systems, and reporting tools, especially those relying on default safety controls which are ineffective against these vectors.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. No official fix or patch links are provided in the data. Until a fix is available, applications should avoid evaluating untrusted templates or implement additional custom resource limits around template evaluation. The vendor advisory recommends adding explicit checks for string multiplication size and BigInteger shift bounds, and enforcing loop limits in builtin functions to prevent unbounded resource consumption.
Technical Details
- Gcve Source
- db.gcve.eu
- Osv Id
- GHSA-xw6w-9jjh-p9cr
- Osv Schema Version
- 1.4.0
- Aliases
- []
- Ecosystems
- ["NuGet"]
- Database Specific Severity
- MODERATE
- Cvss Version
- 3.1
Threat ID: 6a4c346027e9c79719600899
Added to database: 07/06/2026, 23:04:00 UTC
Last enriched: 07/06/2026, 23:37:19 UTC
Last updated: 07/31/2026, 12:27:30 UTC
Views: 13
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
External Links
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.