Mar 25, 2026·5 min read·27 visits
Scriban versions prior to 7.0.0 fail to cumulatively track string allocations across template loops. Attackers can leverage this bypass to allocate gigabytes of memory using default settings, crashing the host .NET application.
The Scriban template engine for .NET contains a flaw in its memory allocation limiting logic. An attacker who can supply malicious templates can bypass the `LimitToString` safety mechanism, causing the engine to allocate excessive memory. This leads to an Out-of-Memory (OOM) condition and subsequent application crash, resulting in a Denial of Service (DoS).
Scriban is a popular text templating engine and parser designed for the .NET framework. It is frequently integrated into applications that require dynamic content generation, such as email templating services, static site generators, and web applications. When processing untrusted user input, templating engines must strictly control resource consumption to prevent abuse.
Vulnerability GHSA-M2P3-HWV5-XPQW identifies a flaw in Scriban's resource limitation controls, specifically categorized under CWE-770 (Allocation of Resources Without Limits or Throttling). The vulnerability allows an attacker to construct a specialized template that systematically bypasses the engine's built-in string allocation limits. This bypass results in unbounded memory consumption during the template evaluation and rendering phases.
All versions of the Scriban NuGet package prior to version 7.0.0 are vulnerable to this issue. Exploitation requires the target application to accept and evaluate templates provided by an attacker. A successful attack consumes the host system's available memory, predictably resulting in a Denial of Service (DoS) for the entire application environment.
The Scriban engine implements a safety setting named LimitToString to prevent excessive memory allocation during string conversion and generation. Since commit b5ac4bf, this limit has defaulted to 1,048,576 bytes (1MB). The vulnerability exists because this specific safety check was enforced on a per-expression basis rather than cumulatively across the entire template execution lifecycle.
Internally, the engine tracks the size of the current string being constructed using the _currentToStringLength variable. When a top-level string conversion operation completes, the engine evaluates the condition _objectToStringLevel == 0. When this condition evaluates to true, the engine resets the _currentToStringLength counter back to zero, erasing the record of previous allocations.
This counter reset behavior introduces a logical flaw when combined with template loop constructs. An attacker can define a loop where each individual iteration generates a distinct string that remains just under the 1MB threshold. Because the tracking counter resets after each expression evaluates, the engine never triggers the LimitToString violation exception, allowing aggregate memory allocations to grow unboundedly.
Exploiting this vulnerability relies on combining the per-expression limit bypass with Scriban's default loop iteration limits. By default, Scriban enforces a LoopLimit of 1,000 iterations to prevent infinite loops. An attacker can construct a payload that maximizes memory allocation within these default boundaries without triggering any exceptions.
The following Proof of Concept (PoC) demonstrates the attack using standard TemplateContext settings. The payload instructs the engine to iterate 1,000 times. During each iteration, the engine performs string multiplication to generate a string of 1,048,575 characters (assuming single-byte characters, this equals 1,048,575 bytes).
using Scriban;
// This payload relies on default TemplateContext settings:
// LoopLimit = 1000
// LimitToString = 1,048,576 (1MB)
var template = Template.Parse(@"{{ for i in 1..1000 }}{{ 'a' * 1048575 }}{{ end }}");
// Each iteration generates a string of 1,048,575 bytes.
// 1,048,575 < 1,048,576 (passes the LimitToString check).
// Total allocation = 1,000 * 1,048,575 bytes ≈ 1GB.
template.Render(); Because 1,048,575 bytes is strictly less than the 1,048,576-byte LimitToString threshold, the per-expression check passes. The engine then resets the tracking counter. Across 1,000 iterations, the application allocates approximately 1 gigabyte of memory in rapid succession. In environments with concurrency, multiple identical requests will quickly exhaust system memory.
The primary impact of this vulnerability is a high-severity Denial of Service (DoS) affecting the availability of the host application. In the .NET runtime environment, an unhandled OutOfMemoryException typically cannot be caught and safely recovered from using standard exception handling mechanisms. When the runtime fails to allocate requested memory, it terminates the hosting process entirely.
Process termination affects all users currently interacting with the application, not just the attacker executing the malicious payload. Any active transactions, background processing tasks, or in-memory state will be lost when the process terminates. If the application runs within a containerized environment (such as Docker or Kubernetes) with strict memory quotas, the orchestrator will forcibly kill the container via an OOMKilled signal.
Depending on the application architecture, the required privileges for exploitation range from Low to None. If the application exposes template generation features to unauthenticated users over a network, an attacker can trigger the OOM condition remotely with a single HTTP request. There is no impact on confidentiality or integrity, as the vulnerability does not expose sensitive data or allow arbitrary code execution.
The vendor addressed this vulnerability in Scriban version 7.0.0. The patch modifies the memory tracking logic to enforce cumulative string allocation limits across the entire template execution context, rather than on a per-expression basis. Developers must upgrade all vulnerable Scriban package references to version 7.0.0 or later to ensure complete protection.
For environments where immediate patching is not technically feasible, developers can implement manual mitigations by explicitly restricting the TemplateContext settings. Administrators should instantiate the TemplateContext and explicitly set both LimitToString and LoopLimit to highly restrictive values tailored to the specific operational requirements of the application. This reduces the maximum possible memory allocation a single template execution can trigger.
As a defense-in-depth measure, security teams should implement resource quotas at the infrastructure level. Configuring memory limits via cgroups in Linux, container memory limits in Docker, or App Service plans in Azure ensures that an OOM condition within the application process does not compromise the underlying host or other co-located services.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Scriban Scriban | < 7.0.0 | 7.0.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-770 |
| Attack Vector | Network |
| Impact | Denial of Service (DoS) |
| CVSS v3.1 | 6.5 (Moderate) |
| Exploit Status | PoC Available |
| Privileges Required | Low / None |
Allocation of Resources Without Limits or Throttling
An unsafe execution vulnerability exists in the Bazar form field calculator (CalcField.php) of YesWiki prior to version 4.6.6. The application attempts to validate mathematical formulas using a complex recursive regular expression before passing them to the PHP eval() function. This design leads to both Regular Expression Denial of Service (ReDoS) and Remote Code Execution (RCE) via validation bypass.
An infinite loop vulnerability exists in the pure-Python PDF library pypdf prior to version 6.13.1. When parsing or merging a crafted PDF file containing a cyclic Article/Thread structure, the library fails to exit its traversal loop. This causes the executing thread to hang indefinitely, leading to 100% CPU utilization and a denial of service. The vulnerability is tracked under CVE-2026-54651 and GHSA-g9xf-7f8q-9mcj, with a CVSS base score of 5.5. This technical report provides a root cause analysis, code review, exploitation vectors, and mitigation paths.
The Netty-based HTTP Client in the Micronaut framework fails to enforce a maximum redirect ceiling by default when processing HTTP responses. This permits remote, attacker-controlled servers to trigger continuous, infinite redirect loops. The resulting recursion causes high CPU utilization, thread starvation, and potential memory exhaustion, inducing a Denial of Service (DoS) state in client-side applications.
An information disclosure vulnerability exists in the Micronaut Framework's HTTP client components. The client fails to clear sensitive authorization headers and cookies when following redirects across different origins. If an application using the vulnerable client communicates with an endpoint that issues a redirect to an external host, the client will forward the original credentials, leading to potential token theft and session hijacking.
GHSA-52vm-mxx8-f227 is a dual-vector security flaw in phantom-audio (<= 1.3.0). The vulnerability allows arbitrary file writes due to unconfined Model Context Protocol (MCP) tool paths when the PHANTOM_OUTPUT_DIR environment variable is not defined. Concurrently, the platform lacks validation controls during the decompression of highly compressed audio files, resulting in resource-exhaustion denial of service and downstream parsing vulnerability exposure.
An authenticated path traversal and arbitrary local file read vulnerability exists in Craft CMS versions 4.x up to 4.17.6 within the assets/icon endpoint and Assets helper classes. By exploiting this vulnerability, an authenticated user can traverse directories and read arbitrary .svg files on the server's filesystem, or execute Stored Cross-Site Scripting (XSS) if they can upload a malicious SVG.