{"id":4997,"date":"2025-08-26T22:17:18","date_gmt":"2025-08-27T05:17:18","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/semantic-kernel\/?p=4997"},"modified":"2025-08-26T22:18:21","modified_gmt":"2025-08-27T05:18:21","slug":"encoding-changes-for-template-arguments-in-semantic-kernel","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/encoding-changes-for-template-arguments-in-semantic-kernel\/","title":{"rendered":"Encoding Changes for Template Arguments in Semantic Kernel"},"content":{"rendered":"<p>In previous versions of the Semantic Kernel, the encoding of template arguments was performed automatically if the argument type was a <code>string<\/code>. The encoding was not applied for custom types, anonymous types, or collections.<\/p>\n<p>With the latest changes, we&#8217;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.<\/p>\n<p>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 <a href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/concepts\/prompts\/\">official documentation<\/a>.<\/p>\n<h2><strong>Encoding for Complex Types<\/strong><\/h2>\n<p>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.<\/p>\n<p>To address this, the SDK now throws an exception in such cases, forcing explicit manual encoding and configuration.<\/p>\n<h2><strong>Changes in the Latest Version and Potential Errors<\/strong><\/h2>\n<p>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.\nIf your code uses Handlebars or Liquid templates with complex arguments (e.g., objects with user-input properties), you&#8217;ll encounter this change. The exception message will guide you to manually encode the data and set <code>AllowDangerouslySetContent<\/code> to <code>true<\/code> for the relevant input variables.\nThis shift ensures stricter, more secure rules, reducing the risk of vulnerabilities while maintaining flexibility for advanced use cases.<\/p>\n<h2><strong>How to Update Your Code<\/strong><\/h2>\n<p>To resolve this, you must manually encode any potentially unsafe data within complex types and explicitly disable automatic encoding for those arguments by setting <code>AllowDangerouslySetContent<\/code> to <code>true<\/code> in the prompt template configuration.<\/p>\n<h3><strong>.NET Example<\/strong><\/h3>\n<p>Here&#8217;s an example of the code before the change:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">var arguments = new KernelArguments()\r\n{\r\n    { \"customer\", new\r\n        {\r\n            firstName = userInput.FirstName,\r\n            lastName = userInput.LastName,\r\n        }\r\n    }\r\n};\r\n\r\nvar templateFactory = new LiquidPromptTemplateFactory();\r\nvar promptTemplateConfig = new PromptTemplateConfig()\r\n{\r\n    TemplateFormat = \"liquid\"\r\n};\r\n\r\nvar promptTemplate = templateFactory.Create(promptTemplateConfig);\r\n\/\/ The following line will throw an exception now, because of the complex type passed as argument and enabled encoding\r\nvar renderedPrompt = await promptTemplate.RenderAsync(kernel, arguments);<\/code><\/pre>\n<p>And after the change:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">var arguments = new KernelArguments()\r\n{\r\n    { \"customer\", new\r\n        {\r\n            \/\/ Perform encoding for each property of complex type\r\n            firstName = HttpUtility.HtmlEncode(userInput.FirstName),\r\n            lastName = HttpUtility.HtmlEncode(userInput.LastName),\r\n        }\r\n    }\r\n};\r\n\r\nvar templateFactory = new LiquidPromptTemplateFactory();\r\nvar promptTemplateConfig = new PromptTemplateConfig()\r\n{\r\n    TemplateFormat = \"liquid\",\r\n    InputVariables = new()\r\n    {\r\n        \/\/ We set AllowDangerouslySetContent to 'true' because each property of this argument is encoded manually\r\n        new() { Name = \"customer\", AllowDangerouslySetContent = true },\r\n    }\r\n};\r\n\r\nvar promptTemplate = templateFactory.Create(promptTemplateConfig);\r\n\/\/ No exception, because we disabled encoding for arguments due to manual encoding\r\nvar renderedPrompt = await promptTemplate.RenderAsync(kernel, arguments);<\/code><\/pre>\n<h3><strong>Python Example<\/strong><\/h3>\n<p>Here&#8217;s an example of the code before the change:<\/p>\n<pre class=\"prettyprint language-python\"><code class=\"language-python\">arguments = {\r\n    \"customer\": {\r\n        \"first_name\": user_input.first_name,\r\n        \"last_name\": user_input.last_name,\r\n    }\r\n}\r\n\r\nprompt_template_config = PromptTemplateConfig(\r\n    template_format=\"handlebars\"\r\n)\r\n\r\nprompt_template = HandlebarsPromptTemplate(prompt_template_config=prompt_template_config)\r\n# The following line will throw an exception now, because of the complex type passed as argument and enabled encoding\r\nrendered_prompt = await prompt_template.render(kernel, arguments)<\/code><\/pre>\n<p>And after the change:<\/p>\n<pre class=\"prettyprint language-python\"><code class=\"language-python\">arguments = {\r\n    \"customer\": {\r\n        # Perform encoding for each property of the complex type\r\n        \"first_name\": escape(user_input.first_name),\r\n        \"last_name\": escape(user_input.last_name),\r\n    }\r\n}\r\n\r\nprompt_template_config = PromptTemplateConfig(\r\n    template=template,\r\n    template_format=\"handlebars\",\r\n    input_variables=[\r\n        # We set allow_dangerously_set_content to True because each property of this argument is encoded manually\r\n        InputVariable(name=\"customer\", allow_dangerously_set_content=True),\r\n    ]\r\n)\r\n\r\nprompt_template = HandlebarsPromptTemplate(prompt_template_config=prompt_template_config)\r\n# No exception, because we disabled encoding for arguments due to manual encoding\r\nrendered_prompt = await prompt_template.render(kernel, arguments)<\/code><\/pre>\n<p>In this update:<\/p>\n<ol>\n<li>Manually encode properties using methods like <code>HttpUtility.HtmlEncode<\/code> (or equivalent for your templating engine) to sanitize user input.<\/li>\n<li>Add <code>InputVariables<\/code> to the <code>PromptTemplateConfig<\/code> and set <code>AllowDangerouslySetContent = true<\/code> for complex arguments where you&#8217;ve handled encoding yourself. This tells the SDK to skip automatic encoding for that variable.<\/li>\n<\/ol>\n<p>Apply similar changes for Handlebars or other supported templates. Always test rendered output to ensure encoding is applied correctly without breaking functionality.<\/p>\n<h2><strong>Summary<\/strong><\/h2>\n<p>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.<\/p>\n<p>We\u2019re 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 <a href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/discussions\">discussion boards<\/a> on GitHub! We would also love your support\u2014if you&#8217;ve enjoyed using Semantic Kernel, give us a star on <a href=\"https:\/\/github.com\/microsoft\/semantic-kernel\">GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&#8217;ve introduced stricter rules: if automatic encoding is enabled (the default behavior), an exception will now be [&hellip;]<\/p>\n","protected":false},"author":156732,"featured_media":5015,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[78,17,34,1],"tags":[],"class_list":["post-4997","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-announcements","category-python-2","category-semantic-kernel"],"acf":[],"blog_post_summary":"<p>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&#8217;ve introduced stricter rules: if automatic encoding is enabled (the default behavior), an exception will now be [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4997","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/users\/156732"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/comments?post=4997"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4997\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/5015"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=4997"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=4997"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=4997"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}