Scriban TemplateContext Cache Poisoning: MemberFilter Bypass via Accessor Reuse
Scriban's TemplateContext caches type accessors by Type alone, ignoring MemberFilter changes. Reusing a context with a tightened filter after a permissive render allows attackers to access members that should be hidden, bypassing sandbox restrictions.
CVE References
Affected
Vulnerability Description
Scriban's TemplateContext implements a cache for TypedObjectAccessor objects keyed solely by Type, without accounting for the MemberFilter or MemberRenamer configurations. The TypedObjectAccessor constructor precomputes the set of exposed members based on the current filter state. However, TemplateContext.Reset() does not invalidate this cache, meaning that if the same context is reused with a stricter MemberFilter after an initial render with a permissive filter, the old accessor—with its broader member exposure—remains in use. This violates the principle of least privilege that sandboxing policies depend on.
PoC Significance
This vulnerability proves that security boundaries enforced via dynamic policy changes are ineffective when the same TemplateContext instance is reused across multiple render operations. The attack does not require template injection or code execution; it only requires:
- A permissive
MemberFilterallowing access to sensitive members during an initial render - Subsequent tightening of the
MemberFilteron the same context instance - Another template render using the same context
The precomputed member set in the cached accessor makes this 100% reliable—there is no runtime re-evaluation. This is particularly critical in multi-tenant or dynamic policy scenarios where rendering contexts are pooled for performance.
Detection Guidance
Log Indicators:
- Template renders where
TemplateContext.MemberFilteris modified between operations on the same instance - Unexpected property access in template output that contradicts current
MemberFilterrules - Repeated calls to
TemplateContext.GetMemberAccessor()that return identical accessor objects despite filter changes
Code Review:
- Search for patterns reusing
TemplateContextinstances across filter changes - Audit calls to
TemplateContext.Reset()to verify cache invalidation expectations - Identify scenarios where
MemberFilteris tightened post-initialization
Runtime Detection (if instrumentation possible):
- Monitor
_memberAccessorscache hits afterMemberFiltermodifications - Track accessor creation timestamps vs. filter change timestamps
Mitigation Steps
- Patch: Update Scriban to a version where
TemplateContext.Reset()clears_memberAccessorsor where the cache key includesMemberFilteridentity - Workaround: Create a fresh
TemplateContextfor each filter policy change rather than reusing instances - Configuration: If filter changes are dynamic, consider immutable context instances per security policy tier
- Code Practice: Avoid reusing
TemplateContextacross security boundaries; treat context pooling with extreme caution
Risk Assessment
Likelihood: Moderate to high in real-world scenarios because:
- Scriban docs recommend reusing
TemplateContextfor performance - Multi-tenant SaaS platforms commonly adjust permissions dynamically
- The vulnerability is silent—no error or warning signals the bypass
Threat Actors: Privileged insiders, multi-tenant attackers, supply-chain adversaries with template control can exploit this to exfiltrate sensitive data (credentials, PII, business logic) that should be filtered from templates. Enterprise usage of Scriban in template engines makes this attractive.
Sources