Bug Description
ShowCardActionParser::Deserialize in the shared C++ object model calls AdaptiveCard::Deserialize recursively with no depth limit. A card payload with deeply nested Action.ShowCard actions creates an arbitrarily deep parse tree that overflows the stack when rendered.
There is zero depth tracking anywhere in ParseContext, ShowCardAction, or the renderer code paths. The only incidental barrier is jsoncpp's stackLimit (1000 JSON nesting levels), which still allows ~325 levels of ShowCard nesting to parse successfully.
Steps to Reproduce
- Generate a card with nested ShowCards (e.g. 200 levels):
{
"type": "AdaptiveCard",
"version": "1.5",
"body": [{"type": "TextBlock", "text": "Level 200"}],
"actions": [{
"type": "Action.ShowCard",
"title": "More",
"card": {
"type": "AdaptiveCard",
"version": "1.5",
"body": [{"type": "TextBlock", "text": "Level 199"}],
"actions": [{
"type": "Action.ShowCard",
"title": "More",
"card": { "...repeat 200 times..." }
}]
}
}]
}
Generator script (Python):
import json
def nested_showcard(depth):
if depth == 0:
return {"type": "AdaptiveCard", "version": "1.5", "body": [{"type": "TextBlock", "text": "bottom"}]}
return {
"type": "AdaptiveCard", "version": "1.5",
"body": [{"type": "TextBlock", "text": f"Level {depth}"}],
"actions": [{"type": "Action.ShowCard", "title": "More", "card": nested_showcard(depth - 1)}]
}
with open("nested_showcard_200.json", "w") as f:
json.dump(nested_showcard(200), f)
- Parse with AdaptiveCard::DeserializeFromString succeeds with no error, creates 200 nested AdaptiveCard objects
- Render the parsed card stack overflow crash
Verified Behavior
Tested by building a standalone C++ binary against the ObjectModel library:
+----------------+-----------+--------------+--------------------------+
| ShowCard Depth | JSON Size | Parse Result | Parsed Tree Depth |
+----------------+-----------+--------------+--------------------------+
| 5 | 825 bytes | OK | 5 (full tree) |
| 50 | 7.5 KB | OK | 50 (full tree) |
| 200 | 30 KB | OK | 200 (full tree) |
| 325 | 49 KB | OK | 325 (full tree) |
| 350 | 53 KB | Fails | jsoncpp stackLimit hit |
+----------------+-----------+--------------+--------------------------+
Impact
- All renderers using the shared C++ model are affected (UWP, WinUI3, Android, iOS)
- In Windows Widgets: A 3rd-party widget can send this payload → WidgetBoard.exe crashes with STATUS_STACK_OVERFLOW (0xC00000FD)
- The crash is 100% reproducible on any device at any DPI —> unlike #9343 which requires 150% display scale
- The payload is small (~30-50 KB) and trivial to generate
Expected Behavior
The parser should enforce a maximum ShowCard nesting depth (e.g. 5 levels) and emit a parse warning when exceeded. No real-world Adaptive Card nests ShowCards deeper than 2-3 levels.
Environment
- Component: Shared C++ ObjectModel (ObjectModel)
- Affects: All platforms using the shared model (UWP, WinUI3, Android, iOS)
- AdaptiveCards version: Current main branch (verified May 2026)
Related
#9343 —> Different root cause (Carousel + long text + 150% DPI → XAML measurement crash), but same general category: card payload crashing the renderer with no defensive limits
Bug Description
ShowCardActionParser::Deserialize in the shared C++ object model calls AdaptiveCard::Deserialize recursively with no depth limit. A card payload with deeply nested Action.ShowCard actions creates an arbitrarily deep parse tree that overflows the stack when rendered.
There is zero depth tracking anywhere in ParseContext, ShowCardAction, or the renderer code paths. The only incidental barrier is jsoncpp's stackLimit (1000 JSON nesting levels), which still allows ~325 levels of ShowCard nesting to parse successfully.
Steps to Reproduce
Generator script (Python):
Verified Behavior
Tested by building a standalone C++ binary against the ObjectModel library:
+----------------+-----------+--------------+--------------------------+
| ShowCard Depth | JSON Size | Parse Result | Parsed Tree Depth |
+----------------+-----------+--------------+--------------------------+
| 5 | 825 bytes | OK | 5 (full tree) |
| 50 | 7.5 KB | OK | 50 (full tree) |
| 200 | 30 KB | OK | 200 (full tree) |
| 325 | 49 KB | OK | 325 (full tree) |
| 350 | 53 KB | Fails | jsoncpp stackLimit hit |
+----------------+-----------+--------------+--------------------------+
Impact
Expected Behavior
The parser should enforce a maximum ShowCard nesting depth (e.g. 5 levels) and emit a parse warning when exceeded. No real-world Adaptive Card nests ShowCards deeper than 2-3 levels.
Environment
Related
#9343 —> Different root cause (Carousel + long text + 150% DPI → XAML measurement crash), but same general category: card payload crashing the renderer with no defensive limits