Skip to main content
Press slash or control plus K to focus the search. Use the arrow keys to navigate results and press enter to open a threat.
Reconnecting to live updates…

Scriban has Uncontrolled Recursion in `object.to_json` Causing Unrecoverable Process Crash via StackOverflowException

0
High
Published: 03/24/2026 (03/24/2026, 22:15:13 UTC)
Source: GCVE Database
Product: Scriban

Description

## Summary The `object.to_json` builtin function in Scriban performs recursive JSON serialization via an internal `WriteValue()` static local function that has no depth limit, no circular reference detection, and no stack overflow guard. A Scriban template containing a self-referencing object passed to `object.to_json` triggers unbounded recursion, causing a `StackOverflowException` that terminates the hosting .NET process. This is a fatal, unrecoverable crash — `StackOverflowException` cannot be caught by user code in .NET. ## Details The vulnerable code is the `WriteValue()` static local function at `src/Scriban/Functions/ObjectFunctions.cs:494`: ```csharp static void WriteValue(TemplateContext context, Utf8JsonWriter writer, object value) { var type = value?.GetType() ?? typeof(object); if (value is null || value is string || value is bool || type.IsPrimitiveOrDecimal() || value is IFormattable) { JsonSerializer.Serialize(writer, value, type); } else if (value is IList || type.IsArray) { writer.WriteStartArray(); foreach (var x in context.ToList(context.CurrentSpan, value)) { WriteValue(context, writer, x); // recursive, no depth check } writer.WriteEndArray(); } else { writer.WriteStartObject(); var accessor = context.GetMemberAccessor(value); foreach (var member in accessor.GetMembers(context, context.CurrentSpan, value)) { if (accessor.TryGetValue(context, context.CurrentSpan, value, member, out var memberValue)) { writer.WritePropertyName(member); WriteValue(context, writer, memberValue); // recursive, no depth check } } writer.WriteEndObject(); } } ``` This function has **none** of the safety mechanisms present in other recursive paths: - `ObjectToString()` at `TemplateContext.Helpers.cs:98` checks `ObjectRecursionLimit` (default 20) - `EnterRecursive()` at `TemplateContext.cs:957` calls `RuntimeHelpers.EnsureSufficientExecutionStack()` - `CheckAbort()` at `TemplateContext.cs:464` also calls `EnsureSufficientExecutionStack()` The `WriteValue()` function bypasses all of these because it is a static local function that only takes the `TemplateContext` for member access — it never calls `EnterRecursive()`, never checks `ObjectRecursionLimit`, and never calls `EnsureSufficientExecutionStack()`. **Execution flow:** 1. Template creates a ScriptObject: `{{ x = {} }}` 2. Sets a self-reference: `x.self = x` — stores a reference in `ScriptObject.Store` dictionary 3. Pipes to `object.to_json`: `x | object.to_json` → calls `ToJson()` at line 477 4. `ToJson()` calls `WriteValue(context, writer, value)` at line 488 5. `WriteValue` enters the `else` branch (line 515), gets members via accessor, finds "self" 6. `TryGetValue` returns `x` itself, `WriteValue` recurses with the same object — infinite loop 7. `StackOverflowException` is thrown — **fatal, cannot be caught, process terminates** ## PoC ```scriban {{ x = {}; x.self = x; x | object.to_json }} ``` In a hosting application: ```csharp using Scriban; // This will crash the entire process with StackOverflowException var template = Template.Parse("{{ x = {}; x.self = x; x | object.to_json }}"); var result = template.Render(); // FATAL: process terminates here ``` Even without circular references, deeply nested objects can exhaust the stack since no depth limit is enforced: ```scriban {{ a = {} b = {inner: a} c = {inner: b} d = {inner: c} # ... continue nesting ... result = deepest | object.to_json }} ``` ## Impact - **Process crash DoS**: Any application embedding Scriban for user-provided templates (CMS platforms, email template engines, report generators, static site generators) can be crashed by a single malicious template. The crash is unrecoverable — `StackOverflowException` terminates the .NET process. - **No try/catch protection possible**: Unlike most exceptions, `StackOverflowException` cannot be caught by application code. The hosting application cannot wrap `template.Render()` in a try/catch to survive this. - **No authentication required**: `object.to_json` is a default builtin function (registered in `BuiltinFunctions.cs`), available in all Scriban templates unless explicitly removed. - **Trivial to exploit**: The PoC is a single line of template code. ## Recommended Fix Add a depth counter parameter to `WriteValue()` and check it against `ObjectRecursionLimit`, consistent with how `ObjectToString` is protected. Also add `EnsureSufficientExecutionStack()` as a safety net: ```csharp static void WriteValue(TemplateContext context, Utf8JsonWriter writer, object value, int depth = 0) { if (context.ObjectRecursionLimit != 0 && depth > context.ObjectRecursionLimit) { throw new ScriptRuntimeException(context.CurrentSpan, $"Exceeding object recursion limit `{context.ObjectRecursion

CVSS v3.1

Score 7.5high

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Affected software

NuGetghsa
Scriban
Affected versions
<7.0.0
NuGetghsa
Scriban.Signed
Affected versions
<7.0.0

Run on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.

AI-Powered Analysis

Machine-generated threat intelligence

AILast updated: 07/06/2026, 23:33:23 UTC

Technical Analysis

The `object.to_json` builtin function in Scriban recursively serializes objects to JSON via a static local function `WriteValue()` that does not enforce any recursion depth limit, circular reference detection, or stack overflow protection. When a self-referencing object or deeply nested structure is passed to `object.to_json`, `WriteValue()` recurses infinitely, causing a StackOverflowException that terminates the hosting .NET process. Unlike other recursive paths in Scriban, `WriteValue()` bypasses safeguards such as `ObjectRecursionLimit` checks and `EnsureSufficientExecutionStack()`. This results in a fatal, unrecoverable crash that cannot be caught by user code. The vulnerability affects all Scriban versions before 7.0.0 and can be triggered by a simple template snippet.

Potential Impact

This vulnerability causes a denial-of-service condition by crashing the entire hosting process due to an unrecoverable StackOverflowException. Applications embedding Scriban for user-provided templates (such as CMS platforms, email template engines, report generators, or static site generators) can be terminated by a single malicious template using `object.to_json` with self-referencing or deeply nested objects. There is no way for the hosting application to catch or recover from this exception, making the crash fatal. No authentication or special privileges are required to exploit this vulnerability, and the exploit is trivial to execute.

Mitigation Recommendations

Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. The recommended fix is to add a recursion depth counter and enforce the `ObjectRecursionLimit` in the `WriteValue()` function, along with calling `EnsureSufficientExecutionStack()` to prevent stack overflow. Until an official fix is available, consider removing or disabling the `object.to_json` builtin function in Scriban templates to prevent exploitation.

Pro Console: star threats, build custom feeds, automate alerts via Slack, email & webhooks.Upgrade to Pro

Technical Details

Gcve Source
db.gcve.eu
Osv Id
GHSA-xcx6-vp38-8hr5
Osv Schema Version
1.4.0
Aliases
[]
Ecosystems
["NuGet"]
Database Specific Severity
HIGH
Cvss Version
3.1

Threat ID: 6a4c346127e9c79719600acf

Added to database: 07/06/2026, 23:04:01 UTC

Last enriched: 07/06/2026, 23:33:23 UTC

Last updated: 07/31/2026, 12:27:30 UTC

Views: 7

Community Reviews

0 reviews

Crowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.

Sort by
Loading community insights…

Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.

Actions

PRO

Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.

Please log in to the Console to use AI analysis features.

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

Breach by OffSeqOFFSEQFRIENDS — 25% OFF

Check if your credentials are on the dark web

Instant breach scanning across billions of leaked records. Free tier available.

Scan now
OffSeq TrainingCredly Certified

Lead Pen Test Professional

Technical5-day eLearningPECB Accredited
View courses