CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-XCX6-VP38-8HR5
7.5

GHSA-xcx6-vp38-8hr5: Uncontrolled Recursion leading to Denial of Service in Scriban

Alon Barad
Alon Barad
Software Engineer

Mar 25, 2026·6 min read·3 visits

PoC Available

Executive Summary (TL;DR)

Scriban < 7.0.0 allows unauthenticated attackers to crash the host application via a StackOverflowException by piping deeply nested or self-referencing objects to the `object.to_json` function. This results in a complete Denial of Service. The issue is fixed in version 7.0.0.

Scriban versions prior to 7.0.0 suffer from an uncontrolled recursion vulnerability within the `object.to_json` built-in function. By passing a specially crafted self-referencing or deeply nested object to this function, an attacker can trigger an infinite recursive loop. This exhausts the execution stack, resulting in an uncatchable StackOverflowException that immediately terminates the hosting .NET process.

Vulnerability Overview

Scriban is a widely used scripting engine and template parsing library for .NET applications. It provides built-in functions for data manipulation, including object.to_json, which serializes internal objects into JSON string representations. This function allows template authors to easily output variables and internal data structures to the rendered view.

A critical vulnerability exists within the implementation of this JSON serialization function in versions prior to 7.0.0. The engine fails to implement proper recursion depth controls or circular reference tracking when traversing object properties. When processing complex objects, the parser blindly follows nested properties without validating the traversal depth against the system's execution capabilities.

Consequently, an attacker who can supply arbitrary template content can force the engine into an infinite recursion loop. This results in a StackOverflowException that immediately terminates the hosting .NET process, leading to a complete Denial of Service (DoS). The vulnerability operates over the network with low complexity and zero required privileges, assuming the target application exposes template compilation to unauthenticated users.

Root Cause Analysis

The root cause of this vulnerability lies in the WriteValue internal static local function, located within src/Scriban/Functions/ObjectFunctions.cs. This function is responsible for recursively traversing object properties and serializing them into a JSON output stream. It is invoked whenever a template pipes an internal object to the object.to_json built-in function.

During standard execution, Scriban employs a centralized mechanism to prevent unbounded recursion using configurable properties like ObjectRecursionLimit. However, the WriteValue function operates independently of these global safety mechanisms. It accepts a TemplateContext object strictly for member access operations but neglects to invoke the engine's EnterRecursive() or CheckAbort() safeguards.

Furthermore, the implementation lacks circular reference detection. When the function processes an object that contains a reference to itself, it continuously re-evaluates the same memory structure. The absence of a recursion depth counter or calls to RuntimeHelpers.EnsureSufficientExecutionStack() ensures the runtime cannot gracefully halt execution before the underlying thread's stack space is entirely consumed.

Code Analysis

The vulnerable implementation of WriteValue strictly handles object traversal without maintaining state regarding the traversal depth. The code iterates over complex object members and recursively calls itself for each nested value, lacking any terminating condition for cyclic graphs.

The remediation strategy introduces two critical control flow changes within the WriteValue function. First, it implements an explicit depth parameter that increments upon each recursive call, checking it against the context's defined recursion limit. Second, it integrates explicit execution stack validation.

// Patched implementation excerpt (v7.0.0)
static void WriteValue(TemplateContext context, Utf8JsonWriter writer, object value, int depth = 0)
{
    if (context.ObjectRecursionLimit != 0 && depth > context.ObjectRecursionLimit)
    {
        throw new ScriptRuntimeException(context.CurrentSpan, "Recursion limit exceeded.");
    }
    RuntimeHelpers.EnsureSufficientExecutionStack();
    
    // ... complex object serialization logic ...
    WriteValue(context, writer, memberValue, depth + 1);
}

This approach guarantees that either the logical depth limit is reached, throwing a catchable ScriptRuntimeException, or the runtime stack check proactively throws an InsufficientExecutionStackException before a fatal crash occurs. The EnsureSufficientExecutionStack method checks the remaining stack space and allows the .NET runtime to safely abort the operation without corrupting the host process.

Exploitation Mechanism

Exploitation requires the ability to supply or modify a Scriban template executed by the target application. No authentication is necessary if the application exposes template rendering to unauthenticated users, such as in web-to-print services, dynamic email generators, or customizable CMS themes.

The attack relies on constructing an object literal with a self-referencing property, followed by passing this object to the object.to_json pipeline. A single line of template code achieves this state and initiates the recursive loop.

{{ x = {}; x.self = x; x | object.to_json }}

Alternatively, an attacker can bypass cyclic tracking entirely by constructing a sufficiently deep nested object structure. The serialization function processes each layer, consuming a stack frame for every nested level, and eventually exhausts the call stack prior to completing the request.

{{ a = {}; b = {inner: a}; c = {inner: b}; deepest | object.to_json }}

Both vectors produce the identical unrecoverable process crash. The exploit succeeds consistently regardless of the underlying operating system or system architecture, relying entirely on the .NET runtime's fixed stack allocation limits.

Impact Assessment

The security impact of this vulnerability is a severe Denial of Service. In .NET runtimes, a StackOverflowException is categorized as a fatal, unrecoverable error. It cannot be intercepted or handled using standard try/catch blocks within application code.

When the vulnerability is triggered, the entire hosting process terminates immediately. This affects the application domain executing the Scriban template, bringing down IIS application pools, Kestrel web servers, or background worker services that host the engine. All active connections are dropped, and all concurrent processing halts.

The attack vector operates over the network with low complexity and zero required privileges. Because the process termination halts the entire service, the availability impact is complete. Service restoration mandates an automated restart policy or manual administrative intervention. In environments without robust high-availability configurations, a single request removes the service from operation.

Remediation and Mitigation

The primary remediation for this vulnerability is upgrading the Scriban NuGet package to version 7.0.0 or later. This release introduces the necessary depth tracking and stack validation logic to gracefully handle deeply nested or cyclic objects.

If immediate upgrading is structurally infeasible, developers must implement a temporary workaround by modifying the execution environment. The object.to_json function can be explicitly unregistered from the BuiltinFunctions context before template execution begins. This prevents the parser from routing untrusted input to the vulnerable serialization logic.

Security teams should also audit application architectures for untrusted template inputs. Running template engines in isolated, resource-constrained execution environments, such as dedicated microservices or ephemeral containers, limits the blast radius of unrecoverable process crashes. Ensuring the host architecture implements automatic restart policies mitigates the duration of the outage.

Official Patches

ScribanScriban 7.0.0 Release Notes and Patch

Technical Appendix

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

Affected Systems

Scriban scripting engine versions prior to 7.0.0Any .NET application rendering user-supplied Scriban templates using default context

Affected Versions Detail

Product
Affected Versions
Fixed Version
Scriban
Scriban
< 7.0.07.0.0
AttributeDetail
Vulnerability ClassUncontrolled Recursion (CWE-674)
Affected Componentobject.to_json (Scriban.Functions.ObjectFunctions)
CVSS Score7.5 (High)
ImpactDenial of Service (Unrecoverable Process Crash)
Attack VectorNetwork / Arbitrary Template Input
Exploitation StatusProof-of-Concept Available
Authentication RequiredNone

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1059Command and Scripting Interpreter
Execution
CWE-674
Uncontrolled Recursion

The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack.

Vulnerability Timeline

Vulnerability discovered and reported to maintainers.
2026-03-01
Scriban version 7.0.0 released with security fix.
2026-03-22
GitHub Security Advisory GHSA-xcx6-vp38-8hr5 published.
2026-03-24

References & Sources

  • [1]GitHub Advisory: Uncontrolled Recursion in Scriban
  • [2]OSV Database Entry
  • [3]Scriban v7.0.0 Release

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.