Summary
TemplateContext.Reset() claims that a TemplateContext can be reused safely on the same thread, but it does not clear CachedTemplates. If an application pools TemplateContext objects and uses an ITemplateLoader that resolves content per request, tenant, or user, a previously authorized include can be served to later renders without calling TemplateLoader.Load() again.
Details
The relevant code path is:
TemplateContext.Reset()only clears output, globals, cultures, and source files insrc/Scriban/TemplateContext.cslines 877–902.CachedTemplatesis initialized once and kept on the context insrc/Scriban/TemplateContext.csline 197.includeresolves templates throughIncludeFunction.Invoke()insrc/Scriban/Functions/IncludeFunction.cslines 29–43.IncludeFunction.Invoke()callsTemplateContext.GetOrCreateTemplate()insrc/Scriban/TemplateContext.cslines 1249–1256.- If a template path is already present in
CachedTemplates, Scriban returns the cached compiled template and does not callTemplateLoader.Load()again.
This becomes a security issue when ITemplateLoader.Load() returns request-dependent content. A first render can prime the cache with an admin-only or tenant-specific template, and later renders on the same reused TemplateContext will receive that stale template even after Reset().
Proof of Concept
Setup
mkdir scriban-poc1
cd scriban-poc1
dotnet new console --framework net8.0
dotnet add package Scriban --version 6.6.0
Program.cs
using Scriban;
using Scriban.Parsing;
using Scriban.Runtime;
var loader = new SwitchingLoader();
var context = new TemplateContext
{
TemplateLoader = loader,
};
var template = Template.Parse("{{ include 'profile' }}");
loader.Content = "admin-only";
Console.WriteLine("first=" + template.Render(context));
context.Reset();
loader.Content = "guest-view";
Console.WriteLine("second=" + template.Render(context));
sealed class SwitchingLoader : ITemplateLoader
{
public string Content { get; set; } = string.Empty;
public string GetPath(TemplateContext context, SourceSpan callerSpan, string templateName) => templateName;
public string Load(TemplateContext context, SourceSpan callerSpan, string templatePath) => Content;
public ValueTask<string> LoadAsync(TemplateContext context, SourceSpan callerSpan, string templatePath)
=> new(Content);
}
Run
dotnet run
Actual Output
first=admin-only
second=admin-only
Expected Output
first=admin-only
second=guest-view
The second render should reload the template after Reset(), but it instead reuses the cached compiled template from the previous render.
Impact
This is a cross-render data isolation issue. Any application that reuses TemplateContext objects and uses a request-dependent ITemplateLoader can leak previously authorized template content across requests, users, or tenants.
The issue impacts applications that:
- Pool or reuse
TemplateContext - Call
Reset()between requests - Use
include - Resolve include content based on request-specific state
GHSA-X6M9-38VM-2XHF has a CVSS score of 8.6 (High). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (7.0.0); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Remediation advice
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is GHSA-X6M9-38VM-2XHF? GHSA-X6M9-38VM-2XHF is a high-severity security vulnerability in scriban (nuget), affecting versions < 7.0.0. It is fixed in 7.0.0.
- How severe is GHSA-X6M9-38VM-2XHF? GHSA-X6M9-38VM-2XHF has a CVSS score of 8.6 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of scriban are affected by GHSA-X6M9-38VM-2XHF? scriban (nuget) versions < 7.0.0 is affected.
- Is there a fix for GHSA-X6M9-38VM-2XHF? Yes. GHSA-X6M9-38VM-2XHF is fixed in 7.0.0. Upgrade to this version or later.
- Is GHSA-X6M9-38VM-2XHF exploitable, and should I be worried? Whether GHSA-X6M9-38VM-2XHF is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether GHSA-X6M9-38VM-2XHF is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix GHSA-X6M9-38VM-2XHF? Upgrade
scribanto 7.0.0 or later.