diff --git a/web/src/ar/common/utils.ts b/web/src/ar/common/utils.ts
index e170d0fe47..0badecb717 100644
--- a/web/src/ar/common/utils.ts
+++ b/web/src/ar/common/utils.ts
@@ -47,3 +47,5 @@ export function getPackageTypesForApiQueryParams(packageTypes: RepositoryPackage
export const encodeFileName = (fileName: string): string => {
return fileName.replace(INVALID_FILENAME_CHARS, '_')
}
+
+export { decodeHtmlEntities } from './utils/decodeHtmlEntities'
diff --git a/web/src/ar/common/utils/decodeHtmlEntities.ts b/web/src/ar/common/utils/decodeHtmlEntities.ts
new file mode 100644
index 0000000000..3e49b1b4ed
--- /dev/null
+++ b/web/src/ar/common/utils/decodeHtmlEntities.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2024 Harness, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Safely decodes HTML entities in a string without XSS vulnerability.
+ * Uses DOMParser which is safer than innerHTML as it doesn't execute scripts.
+ *
+ * @param text - The text containing HTML entities to decode
+ * @returns The decoded text with HTML entities converted to their character equivalents
+ *
+ * @example
+ * decodeHtmlEntities('github.com/rs/xid') // returns 'github.com/rs/xid'
+ * decodeHtmlEntities('<script>alert(1)</script>') // returns '' (safe, no execution)
+ */
+export const decodeHtmlEntities = (text: string): string => {
+ if (!text || typeof text !== 'string') {
+ return text
+ }
+
+ // Use DOMParser which is safer than innerHTML
+ // It parses the content as text/html but doesn't execute scripts
+ const parser = new DOMParser()
+ const doc = parser.parseFromString(text, 'text/html')
+
+ // Extract the text content which automatically decodes entities
+ return doc.documentElement.textContent || text
+}
diff --git a/web/src/ar/components/Form/DeleteModalContent.tsx b/web/src/ar/components/Form/DeleteModalContent.tsx
index cb97f6222a..6a1ce22185 100644
--- a/web/src/ar/components/Form/DeleteModalContent.tsx
+++ b/web/src/ar/components/Form/DeleteModalContent.tsx
@@ -30,6 +30,7 @@ interface DeleteModalContentProps {
content: string
placeholder: string
inputLabel: string
+ inputLabelValue?: string
deleteBtnText?: string
}
@@ -41,9 +42,14 @@ function DeleteModalContent({
content,
placeholder,
inputLabel,
+ inputLabelValue,
deleteBtnText
}: DeleteModalContentProps) {
const { getString } = useStrings()
+
+ // Construct the label with the value appended if provided
+ const finalLabel = inputLabelValue ? `${inputLabel} (${inputLabelValue})` : inputLabel
+
return (
{content}
-
+