From d2edb93340308c588f035b2b1e45b2607c9e7d2a Mon Sep 17 00:00:00 2001
From: zubiden <19638254+zubiden@users.noreply.github.com>
Date: Mon, 27 Apr 2026 14:29:17 +0200
Subject: [PATCH] General: Better validation for HTML attributes (#6892)
---
.../common/helpers/renderTextWithEntities.tsx | 8 +++-
.../middle/composer/helpers/cleanHtml.ts | 32 +++++++++++++--
.../middle/composer/helpers/customEmoji.ts | 41 +++++++++++--------
.../composer/hooks/useMentionTooltip.ts | 5 ++-
src/config.ts | 2 +-
src/serviceWorker/download.ts | 30 ++++++++++++--
src/util/parseHtmlAsFormattedText.ts | 29 ++++---------
7 files changed, 99 insertions(+), 48 deletions(-)
diff --git a/src/components/common/helpers/renderTextWithEntities.tsx b/src/components/common/helpers/renderTextWithEntities.tsx
index 605100c72..721669192 100644
--- a/src/components/common/helpers/renderTextWithEntities.tsx
+++ b/src/components/common/helpers/renderTextWithEntities.tsx
@@ -7,9 +7,11 @@ import type { TextPart, ThreadId } from '../../../types';
import type { TextFilter } from './renderText';
import { ApiMessageEntityTypes } from '../../../api/types';
+import { ensureProtocol } from '../../../util/browser/url';
import buildClassName from '../../../util/buildClassName';
import { copyTextToClipboard } from '../../../util/clipboard';
import { buildFormattedDateHtml } from '../../../util/dates/formattedDate';
+import { escapeHtmlAttribute } from '../../middle/composer/helpers/cleanHtml';
import { buildCustomEmojiHtmlFromEntity } from '../../middle/composer/helpers/customEmoji';
import renderText from './renderText';
@@ -753,7 +755,7 @@ function processEntityAsHtml(
case ApiMessageEntityTypes.TextUrl:
return `${renderedContent}`;
@@ -781,6 +783,10 @@ function getLinkUrl(entityContent: string, entity: ApiMessageEntity) {
return type === ApiMessageEntityTypes.TextUrl && entity.url ? entity.url : entityContent;
}
+function getHtmlLinkUrl(entityContent: string, entity: ApiMessageEntity) {
+ return escapeHtmlAttribute(ensureProtocol(getLinkUrl(entityContent, entity)));
+}
+
function handleBotCommandClick(e: React.MouseEvent) {
getActions().sendBotCommand({ command: e.currentTarget.innerText });
}
diff --git a/src/components/middle/composer/helpers/cleanHtml.ts b/src/components/middle/composer/helpers/cleanHtml.ts
index 45962da36..4c9cd03ba 100644
--- a/src/components/middle/composer/helpers/cleanHtml.ts
+++ b/src/components/middle/composer/helpers/cleanHtml.ts
@@ -2,12 +2,32 @@ import { ApiMessageEntityTypes } from '../../../../api/types';
import { DEBUG } from '../../../../config';
import cleanDocsHtml from '../../../../lib/cleanDocsHtml';
-import { ENTITY_CLASS_BY_NODE_NAME } from '../../../../util/parseHtmlAsFormattedText';
const STYLE_TAG_REGEX = /