Server-Side Template Injection in Prompty C# Jinja2Renderer
Summary
The C# implementation of Prompty (Prompty.Core NuGet package, v2.0.0-beta.4) uses Jinja2.NET.Template to render templates. While Jinja2.NET claims a sandboxed evaluation model, the C# renderer applies NO input sanitization equivalent to the TypeScript fix (safeMemberLookup, safeCallWrap, sanitizeInputs). This is a sibling to GHSA-w28w-gp39-m4p6 (critical SSTI in TypeScript Nunjucks renderer).
Affected Package
- NuGet Prompty.Core version 2.0.0-beta.4 (latest)
- Dependency: Jinja2.NET version 1.4.1
Root Cause
The TypeScript fix (commit 047756f) added three protection layers to the Nunjucks renderer:
- safeMemberLookup - blocks access to proto, constructor, prototype
- safeCallWrap - blocks all function calls from templates
- sanitizeInputs - recursively strips unsafe properties from input objects
The Python renderer uses ImmutableSandboxedEnvironment from jinja2.sandbox.
The C# renderer (Jinja2Renderer.cs) has NONE of these protections. Raw user inputs are passed directly into the template context without sanitization. While Jinja2.NET claims sandboxing, the renderer does not apply the additional input sanitization that was deemed necessary for the TypeScript and Python runtimes.
Vulnerable Code
File: runtime/csharp/Prompty.Core/Jinja2Renderer.cs
public Task RenderAsync(Prompty agent, string template, Dictionary<string, object?> inputs)
{
var (renderInputs, nonces) = RenderHelpers.PrepareRenderInputs(agent, inputs);
var jinja = new Jinja2.NET.Template(template);
var context = new Dictionary<string, object>();
foreach (var kvp in renderInputs)
{
if (kvp.Value is not null)
context[kvp.Key] = kvp.Value;
}
var rendered = jinja.Render(context); // NO sanitizeInputs, NO safeMemberLookup
return Task.FromResult(rendered);
}
Impact
- Severity: High to Critical
- CWE-1336: Improper Neutralization of Special Elements Used in a Template Engine
- Potential RCE when processing untrusted .prompty files
- Novel sibling of GHSA-w28w-gp39-m4p6 in a different runtime (C#/.NET)
References
- TypeScript fix: 047756f
- Existing advisory: GHSA-w28w-gp39-m4p6
- C# source: runtime/csharp/Prompty.Core/Jinja2Renderer.cs
- Python (sandboxed): runtime/python/prompty/prompty/renderers/jinja2.py
Remediation
- Implement input sanitization equivalent to TypeScript sanitizeInputs
- Verify Jinja2.NET sandbox blocks .NET reflection (GetType, Assembly access)
- Block unsafe property access if Jinja2.NET sandbox is insufficient
Reporter
Submitted via secure@microsoft.com per Microsoft SECURITY.md guidelines.
Severity Reassessment
After analyzing Jinja2.NET source code (FunctionCallNodeRenderer.cs), function calls from templates throw NotSupportedException for all functions except 'loop'. This means direct RCE via method calls (GetType().Assembly etc.) is NOT possible in Jinja2.NET.
However, the finding remains valid as:
- Attribute access ({{ obj.property }}) IS supported and unsanitized inputs may expose sensitive properties
- The C# renderer lacks the sanitizeInputs function that was deemed necessary for TypeScript and Python
- This is still a missing-defense-in-depth finding (High information disclosure)
The original report title mentioned RCE but the actual severity is High (information disclosure via unsanitized template context).
Server-Side Template Injection in Prompty C# Jinja2Renderer
Summary
The C# implementation of Prompty (Prompty.Core NuGet package, v2.0.0-beta.4) uses Jinja2.NET.Template to render templates. While Jinja2.NET claims a sandboxed evaluation model, the C# renderer applies NO input sanitization equivalent to the TypeScript fix (safeMemberLookup, safeCallWrap, sanitizeInputs). This is a sibling to GHSA-w28w-gp39-m4p6 (critical SSTI in TypeScript Nunjucks renderer).
Affected Package
Root Cause
The TypeScript fix (commit 047756f) added three protection layers to the Nunjucks renderer:
The Python renderer uses ImmutableSandboxedEnvironment from jinja2.sandbox.
The C# renderer (Jinja2Renderer.cs) has NONE of these protections. Raw user inputs are passed directly into the template context without sanitization. While Jinja2.NET claims sandboxing, the renderer does not apply the additional input sanitization that was deemed necessary for the TypeScript and Python runtimes.
Vulnerable Code
File: runtime/csharp/Prompty.Core/Jinja2Renderer.cs
public Task RenderAsync(Prompty agent, string template, Dictionary<string, object?> inputs)
{
var (renderInputs, nonces) = RenderHelpers.PrepareRenderInputs(agent, inputs);
var jinja = new Jinja2.NET.Template(template);
var context = new Dictionary<string, object>();
foreach (var kvp in renderInputs)
{
if (kvp.Value is not null)
context[kvp.Key] = kvp.Value;
}
var rendered = jinja.Render(context); // NO sanitizeInputs, NO safeMemberLookup
return Task.FromResult(rendered);
}
Impact
References
Remediation
Reporter
Submitted via secure@microsoft.com per Microsoft SECURITY.md guidelines.
Severity Reassessment
After analyzing Jinja2.NET source code (FunctionCallNodeRenderer.cs), function calls from templates throw NotSupportedException for all functions except 'loop'. This means direct RCE via method calls (GetType().Assembly etc.) is NOT possible in Jinja2.NET.
However, the finding remains valid as:
The original report title mentioned RCE but the actual severity is High (information disclosure via unsanitized template context).