Every CVE Search/ Get API key

CVE-2026-74790

Scriban before 7.0.0 MemberFilter Bypass via TemplateContext Cache

9.3 CriticalFix available

Scriban before 7.0.0 caches TypedObjectAccessor by Type only without considering MemberFilter changes, allowing reused TemplateContext instances to expose members that should be hidden. Attackers can access filtered properties and fields by reusing a TemplateContext after tightening its MemberFilter, bypassing sandbox policies across requests or tenants.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
None

Exploit likelihood

0.47%Up 0.2 points since Aug 17, 2026
90%50%10%1%

What each source reports

CVE List Score used 9.3

Scriban before 7.0.0 MemberFilter Bypass via TemplateContext Cache

Scriban before 7.0.0 caches TypedObjectAccessor by Type only without considering MemberFilter changes, allowing reused TemplateContext instances to expose members that should be hidden. Attackers can access filtered properties and fields by reusing a TemplateContext after tightening its MemberFilter, bypassing sandbox policies across requests or tenants.

Record
CVE-2026-74790
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-693
Updated
2026-11-02
EUVDEUVD-2026-59956 9.3

Scriban before 7.0.0 caches TypedObjectAccessor by Type only without considering MemberFilter changes, allowing reused TemplateContext instances to expose members that should be hidden. Attackers can access filtered properties and fields by reusing a TemplateContext after tightening its MemberFilter, bypassing sandbox policies across requests or tenants.

Record
EUVD-2026-59956
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-5wr9-m6jw-xx44 9.1

Scriban: Sandbox escape due to TypedObjectAccessorcache bypassing MemberFilter after TemplateContext reuse

Summary

TemplateContext caches type accessors by Type only, but those accessors are built using the current MemberFilter and MemberRenamer. When a TemplateContext is reused and the filter is tightened for a later render, Scriban still reuses the old accessor and continues exposing members that should now be hidden.

Details

The relevant code path is:

  • TemplateContext.GetMemberAccessor() caches accessors in _memberAccessors by Type in src/Scriban/TemplateContext.cs lines 850–863.
  • For plain .NET objects, GetMemberAccessorImpl() creates a new TypedObjectAccessor(type, _keyComparer, MemberFilter, MemberRenamer) in src/Scriban/TemplateContext.cs lines 909–939.
  • TypedObjectAccessor stores the current filter and precomputes the exposed member set in its constructor and PrepareMembers() in src/Scriban/Runtime/Accessors/TypedObjectAccessor.cs lines 33–40 and 119–179.
  • Member access later goes through ScriptMemberExpression.GetValue() in src/Scriban/Syntax/Expressions/ScriptMemberExpression.cs lines 67–95, which uses the cached accessor.
  • TemplateContext.Reset() does not clear _memberAccessors in src/Scriban/TemplateContext.cs lines 877–902.

As a result, once a permissive accessor has been created for a given type, changing TemplateContext.MemberFilter later does not take effect for that type on the same reused context.

This is especially relevant because the Scriban docs explicitly recommend TemplateContext.MemberFilter for indirect .NET object exposure.


Proof of Concept

Setup

mkdir scriban-poc2
cd scriban-poc2
dotnet new console --framework net8.0
dotnet add package Scriban --version 6.6.0

Program.cs

using System.Reflection;
using Scriban;
using Scriban.Runtime;

var template = Template.Parse("{{ model.secret }}");

var context = new TemplateContext
{
    EnableRelaxedMemberAccess = false
};

var globals = new ScriptObject();
globals["model"] = new SensitiveModel();
context.PushGlobal(globals);

context.MemberFilter = _ => true;
Console.WriteLine("first=" + template.Render(context));

context.Reset();

var globals2 = new ScriptObject();
globals2["model"] = new SensitiveModel();
context.PushGlobal(globals2);

context.MemberFilter = member => member.Name == nameof(SensitiveModel.Public);

Console.WriteLine("second=" + template.Render(context));

sealed class SensitiveModel
{
    public string Public => "ok";
    public string Secret => "leaked";
}

Run

dotnet run

Actual Output

first=leaked
second=leaked

Expected Behavior

The second render should fail or stop exposing Secret, because the filter only allows Public and EnableRelaxedMemberAccess is disabled.

This reproduces a direct filter bypass caused by the stale cached accessor.


Impact

This is a protection-mechanism bypass. Applications that use TemplateContext.MemberFilter as part of their sandbox or object-exposure policy can unintentionally expose hidden members across requests when they reuse a TemplateContext.

The impact includes:

  • Unauthorized read access to filtered properties or fields
  • Unauthorized writes if the filtered member also has a setter
  • Policy bypass across requests, users, or tenants when contexts are pooled
Record
GHSA-5wr9-m6jw-xx44
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-693
Updated
2026-11-02
GitHub AdvisoriesGHSA-6w6f-93jg-2qf5 9.3

Scriban before 7.0.0 caches TypedObjectAccessor by Type only without considering MemberFilter...

Scriban before 7.0.0 caches TypedObjectAccessor by Type only without considering MemberFilter changes, allowing reused TemplateContext instances to expose members that should be hidden. Attackers can access filtered properties and fields by reusing a TemplateContext after tightening its MemberFilter, bypassing sandbox policies across requests or tenants.

Record
GHSA-6w6f-93jg-2qf5
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-693
Updated
2026-11-02
NVD 9.3

Scriban before 7.0.0 caches TypedObjectAccessor by Type only without considering MemberFilter changes, allowing reused TemplateContext instances to expose members that should be hidden. Attackers can access filtered properties and fields by reusing a TemplateContext after tightening its MemberFilter, bypassing sandbox policies across requests or tenants.

Record
CVE-2026-74790
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-693
Updated
2026-11-02
OSV 9.3

Scriban before 7.0.0 MemberFilter Bypass via TemplateContext Cache

Scriban before 7.0.0 caches TypedObjectAccessor by Type only without considering MemberFilter changes, allowing reused TemplateContext instances to expose members that should be hidden. Attackers can access filtered properties and fields by reusing a TemplateContext after tightening its MemberFilter, bypassing sandbox policies across requests or tenants.

Record
CVE-2026-74790
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-693
Updated
2026-11-02
OSVGHSA-5wr9-m6jw-xx44 9.1

Scriban: Sandbox escape due to TypedObjectAccessorcache bypassing MemberFilter after TemplateContext reuse

Summary

TemplateContext caches type accessors by Type only, but those accessors are built using the current MemberFilter and MemberRenamer. When a TemplateContext is reused and the filter is tightened for a later render, Scriban still reuses the old accessor and continues exposing members that should now be hidden.

Details

The relevant code path is:

  • TemplateContext.GetMemberAccessor() caches accessors in _memberAccessors by Type in src/Scriban/TemplateContext.cs lines 850–863.
  • For plain .NET objects, GetMemberAccessorImpl() creates a new TypedObjectAccessor(type, _keyComparer, MemberFilter, MemberRenamer) in src/Scriban/TemplateContext.cs lines 909–939.
  • TypedObjectAccessor stores the current filter and precomputes the exposed member set in its constructor and PrepareMembers() in src/Scriban/Runtime/Accessors/TypedObjectAccessor.cs lines 33–40 and 119–179.
  • Member access later goes through ScriptMemberExpression.GetValue() in src/Scriban/Syntax/Expressions/ScriptMemberExpression.cs lines 67–95, which uses the cached accessor.
  • TemplateContext.Reset() does not clear _memberAccessors in src/Scriban/TemplateContext.cs lines 877–902.

As a result, once a permissive accessor has been created for a given type, changing TemplateContext.MemberFilter later does not take effect for that type on the same reused context.

This is especially relevant because the Scriban docs explicitly recommend TemplateContext.MemberFilter for indirect .NET object exposure.


Proof of Concept

Setup

mkdir scriban-poc2
cd scriban-poc2
dotnet new console --framework net8.0
dotnet add package Scriban --version 6.6.0

Program.cs

using System.Reflection;
using Scriban;
using Scriban.Runtime;

var template = Template.Parse("{{ model.secret }}");

var context = new TemplateContext
{
    EnableRelaxedMemberAccess = false
};

var globals = new ScriptObject();
globals["model"] = new SensitiveModel();
context.PushGlobal(globals);

context.MemberFilter = _ => true;
Console.WriteLine("first=" + template.Render(context));

context.Reset();

var globals2 = new ScriptObject();
globals2["model"] = new SensitiveModel();
context.PushGlobal(globals2);

context.MemberFilter = member => member.Name == nameof(SensitiveModel.Public);

Console.WriteLine("second=" + template.Render(context));

sealed class SensitiveModel
{
    public string Public => "ok";
    public string Secret => "leaked";
}

Run

dotnet run

Actual Output

first=leaked
second=leaked

Expected Behavior

The second render should fail or stop exposing Secret, because the filter only allows Public and EnableRelaxedMemberAccess is disabled.

This reproduces a direct filter bypass caused by the stale cached accessor.


Impact

This is a protection-mechanism bypass. Applications that use TemplateContext.MemberFilter as part of their sandbox or object-exposure policy can unintentionally expose hidden members across requests when they reuse a TemplateContext.

The impact includes:

  • Unauthorized read access to filtered properties or fields
  • Unauthorized writes if the filtered member also has a setter
  • Policy bypass across requests, users, or tenants when contexts are pooled
Record
GHSA-5wr9-m6jw-xx44
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-693
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
scriban
NuGet
before 7.0.0
7.0.0
Scriban.Signed
NuGet
before 7.0.0
7.0.0
scriban
NuGet
before 7.0.0, plus listed versions
0.1.00.10.00.11.00.12.00.12.1
Show 45 moreShow less
0.13.00.14.00.15.00.16.00.2.00.2.10.2.20.3.00.3.10.3.1-pre0280.4.00.5.00.6.00.7.00.9.00.9.0-pre1000.9.11.0.01.0.0-beta-0011.0.0-beta-0021.0.0-beta-0031.0.0-beta-0041.0.0-beta-0051.0.0-beta-0061.1.01.1.11.2.01.2.11.2.21.2.31.2.41.2.51.2.61.2.71.2.81.2.92.0.02.0.0-alpha-0012.0.0-alpha-0022.0.0-alpha-0032.0.0-alpha-0042.0.0-alpha-0052.0.0-alpha-0062.0.12.1.0
7.0.0
Scriban.Signed
NuGet
before 7.0.0, plus listed versions
0.10.00.11.00.12.00.12.10.13.0
Show 45 moreShow less
0.14.00.15.00.16.00.9.00.9.11.0.01.0.0-beta-0011.0.0-beta-0021.0.0-beta-0031.0.0-beta-0041.0.0-beta-0051.0.0-beta-0061.1.01.1.11.2.01.2.11.2.21.2.31.2.41.2.51.2.61.2.71.2.81.2.92.0.02.0.0-alpha-0012.0.0-alpha-0022.0.0-alpha-0032.0.0-alpha-0042.0.0-alpha-0052.0.0-alpha-0062.0.12.1.02.1.12.1.22.1.32.1.43.0.03.0.13.0.23.0.33.0.43.0.53.0.63.0.7
7.0.0

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-74790 is a critical vulnerability (CVSS 9.3) in Scriban, published March 24, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.47%, the 40th percentile. Fixed in scriban 7.0.0.

References

This page doesn't list everything

Left out here: 134 versions. The JSON record has them.

MoveEnter Open