Skip to content

.Net: Bound element nesting depth in XML prompt parsing - #14504

Merged
Roger Barreto (rogerbarreto) merged 2 commits into
microsoft:mainfrom
rogerbarreto:i248r706-bounded-element-traversal
Oct 7, 2026
Merged

Roger Barreto (rogerbarreto) merged 2 commits into
microsoft:mainfrom
rogerbarreto:i248r706-bounded-element-traversal

Conversation

@rogerbarreto

Copy link
Copy Markdown
Member

Motivation and Context

XmlPromptParser converts chat prompts such as <message role="user">...</message> into PromptNode trees that ChatPromptParser turns into a ChatHistory. Each PromptNode stores the serialized inner XML of its element, so the parser re-serializes and decodes the whole remaining subtree at every nesting level. Parse work therefore grows with nesting depth multiplied by prompt size, and the recursive node builder had no depth bound.

Supported chat prompt structure is shallow: message elements with optional text, image, audio, and binary children, plus encoded or CDATA text. This change bounds element nesting so parsing cost stays proportional to prompt size.

Description

  • Add XmlPromptParser.MaxElementDepth (internal, 64, top-level prompt elements count as depth 1, matching the System.Text.Json default maximum depth).
  • After the prompt is loaded and before any PromptNode is built, a single non-recursive walk checks element depth. Prompts nested deeper than the limit return false from TryParse.
  • A rejected prompt takes the existing invalid-XML path: callers such as GetChatMessageContentsAsync(string) send the whole prompt as one user text message, exactly as they already do for malformed XML.
  • Parse work for accepted prompts is bounded by the depth limit times prompt size, and recursion in GetPromptNode is bounded.
  • No public API change. Prompts within the limit, including content items, CDATA, and encoded content, parse exactly as before.

Tests:

  • XmlPromptParserTests: parses two prompts at exactly the maximum depth; rejects one level over and far over the limit; rejects when only a later top-level node exceeds the limit (covers sibling traversal after a max-depth subtree).
  • ChatPromptParserTests: a user message whose content exceeds the limit makes ChatPromptParser.TryParse return false.

Validation

All local runs use -c Debug on .NET SDK 10.0.401.

  • Build with --warnaserror: SemanticKernel.Abstractions (net10.0, net8.0, netstandard2.0), SemanticKernel.UnitTests, Extensions.UnitTests, PromptTemplates.Liquid.UnitTests, Agents.UnitTests, IntegrationTests: 0 warnings, 0 errors.
  • dotnet format --verify-no-changes in mcr.microsoft.com/dotnet/sdk:10.0 for both changed projects: clean.
  • SemanticKernel.UnitTests: 1614/1614 pass, including the 5 new tests. The new over-limit tests fail without the parser change.
  • Extensions.UnitTests (Handlebars) 90/90, PromptTemplates.Liquid.UnitTests 16/16, Agents.UnitTests 504/504 executed tests pass, IntegrationTests CrossLanguage (offline, stubbed HTTP request shape) 37/37.
  • Normal chat prompts produce the same ChatHistory on net10.0, net8.0, and .NET Framework 4.8 (netstandard2.0 asset), and the largest prompts still accepted parse in time proportional to their size.

Contribution Checklist

Each parsed prompt node keeps its serialized subtree, so parse work
grew with nesting depth times prompt size. Reject prompts nested
deeper than 64 elements before building nodes; they take the
existing invalid-XML path and are sent as plain text.
Copilot AI balanced review requested due to automatic review settings September 29, 2026 14:36
@semantic-kernel-automation semantic-kernel-automation Bot added .NET Issue or Pull requests regarding .NET code kernel Issues or pull requests impacting the core kernel kernel.core labels Sep 29, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The iterative limit is correctly enforced before recursive node construction and has appropriate boundary coverage.

Review effort: Balanced
Findings: None

What changed in this PR

Bounds XML prompt nesting depth to prevent excessive parsing work and recursion.

Changes:

  • Adds a 64-element depth limit with iterative validation.
  • Adds boundary, excessive-depth, and sibling traversal tests.
  • Verifies over-depth chat prompts fail parsing.
File Description
XmlPromptParser.cs Implements and documents depth validation.
XmlPromptParserTests.cs Tests depth boundaries and sibling traversal.
ChatPromptParserTests.cs Tests rejection through chat parsing.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@semantic-kernel-automation semantic-kernel-automation Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: No findings
Scope: full PR (1 commit(s)): e306e970769a
Model: gpt-5.6-sol-fast

Overview

The PR adds a non-recursive, full-document element-depth check before recursive PromptNode construction and repeated subtree serialization. Boundary, sibling-traversal, deep-input, and chat-layer tests support the intended 64-element limit, while existing callers preserve rejected prompts through their plain-text fallback. No publishable Critical, High, or Medium defect was established.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.

@rogerbarreto
Roger Barreto (rogerbarreto) added this pull request to the merge queue Oct 7, 2026
Merged via the queue into microsoft:main with commit cc8a15f Oct 7, 2026
18 checks passed
@rogerbarreto
Roger Barreto (rogerbarreto) deleted the i248r706-bounded-element-traversal branch October 7, 2026 08:33

This branch was previously deployed

2 inactive deployments
github-app-auth — b0f614a4 Deployed Oct 5, 2026 by rogerbarreto via add_label #29253
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kernel.core kernel Issues or pull requests impacting the core kernel .NET Issue or Pull requests regarding .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants