In previous versions of the Semantic Kernel, the encoding of template arguments was performed automatically if the argument type was a string
. The encoding was not applied for custom types, anonymous types, or collections.
With the latest changes, we’ve introduced stricter rules: if automatic encoding is enabled (the default behavior), an exception will now be thrown when complex types are used as arguments. This enforces more secure template rendering by requiring developers to handle encoding manually for complex types and explicitly disable automatic encoding for those variables. This change promotes best practices for security, especially when using templating engines like Handlebars or Liquid.
This post explains the problem with the previous approach, the new behavior, and how to update your code to comply with these changes. For more details on template rendering in Semantic Kernel, refer to the official documentation.
Encoding for Complex Types
Automatic encoding is a safeguard against common vulnerabilities, such as template injection, by escaping special characters in strings. However, when dealing with complex types (e.g., custom objects, anonymous types, or collections), the SDK cannot reliably determine how to encode nested properties or elements without risking data corruption or incomplete protection.
To address this, the SDK now throws an exception in such cases, forcing explicit manual encoding and configuration.
Changes in the Latest Version and Potential Errors
Starting with latest .NET and Python Semantic Kernel packages, when rendering templates with encoding enabled, using complex types without proper configuration will raise an exception. This prevents accidental insecure rendering and requires code updates for affected scenarios.
If your code uses Handlebars or Liquid templates with complex arguments (e.g., objects with user-input properties), you’ll encounter this change. The exception message will guide you to manually encode the data and set AllowDangerouslySetContent
to true
for the relevant input variables.
This shift ensures stricter, more secure rules, reducing the risk of vulnerabilities while maintaining flexibility for advanced use cases.
How to Update Your Code
To resolve this, you must manually encode any potentially unsafe data within complex types and explicitly disable automatic encoding for those arguments by setting AllowDangerouslySetContent
to true
in the prompt template configuration.
.NET Example
Here’s an example of the code before the change:
var arguments = new KernelArguments()
{
{ "customer", new
{
firstName = userInput.FirstName,
lastName = userInput.LastName,
}
}
};
var templateFactory = new LiquidPromptTemplateFactory();
var promptTemplateConfig = new PromptTemplateConfig()
{
TemplateFormat = "liquid"
};
var promptTemplate = templateFactory.Create(promptTemplateConfig);
// The following line will throw an exception now, because of the complex type passed as argument and enabled encoding
var renderedPrompt = await promptTemplate.RenderAsync(kernel, arguments);
And after the change:
var arguments = new KernelArguments()
{
{ "customer", new
{
// Perform encoding for each property of complex type
firstName = HttpUtility.HtmlEncode(userInput.FirstName),
lastName = HttpUtility.HtmlEncode(userInput.LastName),
}
}
};
var templateFactory = new LiquidPromptTemplateFactory();
var promptTemplateConfig = new PromptTemplateConfig()
{
TemplateFormat = "liquid",
InputVariables = new()
{
// We set AllowDangerouslySetContent to 'true' because each property of this argument is encoded manually
new() { Name = "customer", AllowDangerouslySetContent = true },
}
};
var promptTemplate = templateFactory.Create(promptTemplateConfig);
// No exception, because we disabled encoding for arguments due to manual encoding
var renderedPrompt = await promptTemplate.RenderAsync(kernel, arguments);
Python Example
Here’s an example of the code before the change:
arguments = {
"customer": {
"first_name": user_input.first_name,
"last_name": user_input.last_name,
}
}
prompt_template_config = PromptTemplateConfig(
template_format="handlebars"
)
prompt_template = HandlebarsPromptTemplate(prompt_template_config=prompt_template_config)
# The following line will throw an exception now, because of the complex type passed as argument and enabled encoding
rendered_prompt = await prompt_template.render(kernel, arguments)
And after the change:
arguments = {
"customer": {
# Perform encoding for each property of the complex type
"first_name": escape(user_input.first_name),
"last_name": escape(user_input.last_name),
}
}
prompt_template_config = PromptTemplateConfig(
template=template,
template_format="handlebars",
input_variables=[
# We set allow_dangerously_set_content to True because each property of this argument is encoded manually
InputVariable(name="customer", allow_dangerously_set_content=True),
]
)
prompt_template = HandlebarsPromptTemplate(prompt_template_config=prompt_template_config)
# No exception, because we disabled encoding for arguments due to manual encoding
rendered_prompt = await prompt_template.render(kernel, arguments)
In this update:
- Manually encode properties using methods like
HttpUtility.HtmlEncode
(or equivalent for your templating engine) to sanitize user input. - Add
InputVariables
to thePromptTemplateConfig
and setAllowDangerouslySetContent = true
for complex arguments where you’ve handled encoding yourself. This tells the SDK to skip automatic encoding for that variable.
Apply similar changes for Handlebars or other supported templates. Always test rendered output to ensure encoding is applied correctly without breaking functionality.
Summary
This update to Semantic Kernel introduces stricter encoding rules for template arguments, throwing exceptions for complex types under automatic encoding to enforce manual sanitization and explicit configuration. It significantly enhances security by preventing potential vulnerabilities in template rendering.
We’re always interested in hearing from you. If you have feedback, questions, or want to discuss further, feel free to reach out to us and the community on the discussion boards on GitHub! We would also love your support—if you’ve enjoyed using Semantic Kernel, give us a star on GitHub.
0 comments
Be the first to start the discussion.