From f19fa4b693cbc8ddab5f9049866397cbdd0af0d3 Mon Sep 17 00:00:00 2001 From: Karan Yadav Date: Fri, 8 May 2026 17:12:55 +0530 Subject: [PATCH] fix: escape input.id before regex construction in StringWithSubstitutions.getReferencedInputs Escape regex metacharacters in input.id before injecting it into a RegExp constructor in shared.ts. Without escaping, a crafted input.id like '(a+)+' causes catastrophic backtracking (ReDoS) when matched against URL templates containing near-match patterns. Affected code path: Action.Http -> StringWithSubstitutions.getReferencedInputs() Standard actions (Submit, Execute, OpenUrl) are NOT affected as they use different code paths that don't call this method. Verified: - Normal input IDs still match correctly (e.g. 'userName' matches {{userName.value}}) - Malicious IDs neutralized (0ms vs 13,350ms with 28 chars) - All 28 existing jest tests pass - TypeScript compilation and webpack build succeed --- source/nodejs/adaptivecards/src/shared.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source/nodejs/adaptivecards/src/shared.ts b/source/nodejs/adaptivecards/src/shared.ts index 321133081d..456d188974 100644 --- a/source/nodejs/adaptivecards/src/shared.ts +++ b/source/nodejs/adaptivecards/src/shared.ts @@ -84,9 +84,13 @@ export class StringWithSubstitutions { if (this._original) { for (const input of inputs) { - const matches = new RegExp("\\{{2}(" + input.id + ").value\\}{2}", "gi").exec( - this._original - ); + const escapedId = input.id + ? input.id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + : ""; + const matches = new RegExp( + "\\{{2}(" + escapedId + ").value\\}{2}", + "gi" + ).exec(this._original); if (matches != null && input.id) { referencedInputs[input.id] = input;