Skip to content

[Security] ReDoS vulnerability in StringWithSubstitutions.getReferencedInputs - input.id injected into regex without escaping #9369

@karan68

Description

@karan68

Target Application

Windows Widgets, Microsoft Teams, Outlook, any host using AdaptiveCards JS renderer with Action.Http registered

Application Operating System

Windows

Schema Version

1.5

Problem Description

In shared.ts line 87, the method StringWithSubstitutions.getReferencedInputs() builds a regular expression by directly concatenating input.id from the card JSON payload into a new RegExp() constructor without escaping regex metacharacters.

The vulnerable code:
const matches = new RegExp("\{{2}(" + input.id + ").value\}{2}", "gi").exec(this._original);

input.id comes from untrusted card JSON. An attacker can set input.id to a value like (a+)+ which contains regex quantifiers. When this regex is executed against a URL template containing a near-match pattern, the regex engine enters catastrophic backtracking (exponential time complexity).

This code path is triggered when a user clicks an Action.Http button. Action.Http is not registered in the default GlobalRegistry, so only hosts that explicitly register HttpAction are affected. Standard actions like Action.Submit and Action.Execute use a different code path (internalGetReferencedInputs in SubmitActionBase) that does not call StringWithSubstitutions.getReferencedInputs and is NOT vulnerable.

Measured impact with 28 characters of near-match content in the URL template:

Unfixed: 13,350ms (browser completely frozen)
Fixed with escapeRegExp: 0ms
The freeze duration doubles with every 2 additional characters. At 40 characters it would take hours.

Expected Outcome

The renderer should safely handle any value of input.id without freezing. Regex metacharacters in input.id should be escaped before being used in a RegExp constructor, or a non-regex approach should be used for matching.

Actual Outcome

When a card contains an Input element with id set to a regex pattern like (a+)+ and an Action.Http with a URL template containing a near-match string like {{aaaaaaaaaaaaaaaaaaaaaaaaaaaaXXXXX}}, clicking the action button causes the browser or widget host to freeze for seconds to minutes due to catastrophic regex backtracking. CPU spikes to 100% on a single core.

Card JSON

{
  "type": "AdaptiveCard",
  "version": "1.5",
  "body": [
    {
      "type": "Input.Text",
      "id": "(a+)+",
      "label": "Enter your name"
    }
  ],
  "actions": [
    {
      "type": "Action.Http",
      "title": "Send",
      "method": "POST",
      "url": "https://example.com/api?name={{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaXXXXX}}"
    }
  ]
}

Repro Steps

  1. Register HttpAction in the global registry: GlobalRegistry.actions.register("Action.Http", HttpAction)
  2. Parse the card JSON shown above using AdaptiveCard.parse()
  3. Render the card using AdaptiveCard.render()
  4. Click the "Send" button
  5. The browser or widget host freezes for 13+ seconds (with 28 'a' characters in the URL template). Increasing the count of 'a' characters makes it exponentially worse.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions