From 1489059a2d746fe4298e0cbcbf2a41512a0e93c3 Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:24:02 +0000 Subject: [PATCH] fix(security): bump linkify-it to 5.0.1 (GHSA-22p9-wv53-3rq4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CVE-2026-48801: linkify-it <=5.0.0 has O(N²) scan-loop complexity that can cause client-side DoS when processing large user-authored messages. - Bump linkify-it 5.0.0 → 5.0.1 in apps/web/package.json - Update pnpm-lock.yaml with patched package resolution - Add MAX_LINKIFY_LENGTH guard in MessageBubble.tsx as defence-in-depth --- apps/web/package.json | 2 +- .../components/cloud-agent-next/MessageBubble.tsx | 12 ++++++++++-- pnpm-lock.yaml | 10 +++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 3aa44ab26d..c4a8026458 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -139,7 +139,7 @@ "js-cookie": "3.0.5", "js-yaml": "4.1.1", "jsonwebtoken": "catalog:", - "linkify-it": "5.0.0", + "linkify-it": "5.0.1", "lucide-react": "0.552.0", "mailgun.js": "12.7.1", "monaco-editor": "0.55.1", diff --git a/apps/web/src/components/cloud-agent-next/MessageBubble.tsx b/apps/web/src/components/cloud-agent-next/MessageBubble.tsx index 8589c43320..d9dab54ea6 100644 --- a/apps/web/src/components/cloud-agent-next/MessageBubble.tsx +++ b/apps/web/src/components/cloud-agent-next/MessageBubble.tsx @@ -26,10 +26,15 @@ import LinkifyIt from 'linkify-it'; const linkify = new LinkifyIt(); +// Cap input length before passing to linkify to prevent O(N²) scan-loop DoS +// (CVE-2026-48801) in case the patched library is ever rolled back. +const MAX_LINKIFY_LENGTH = 50_000; + function TextWithLinks({ text }: { text: string }) { const parts: React.ReactNode[] = []; let lastIndex = 0; - for (const match of linkify.match(text) ?? []) { + const safeText = text.length > MAX_LINKIFY_LENGTH ? '' : text; + for (const match of linkify.match(safeText) ?? []) { if (match.index > lastIndex) { parts.push(text.slice(lastIndex, match.index)); } @@ -46,7 +51,10 @@ function TextWithLinks({ text }: { text: string }) { ); lastIndex = match.lastIndex; } - if (lastIndex < text.length) { + // When safeText === '' (text exceeded limit), show the full original text unlinked. + if (safeText.length < text.length) { + parts.push(text); + } else if (lastIndex < text.length) { parts.push(text.slice(lastIndex)); } return <>{parts}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6cc128b24..b095975081 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -891,8 +891,8 @@ importers: specifier: 'catalog:' version: 9.0.3 linkify-it: - specifier: 5.0.0 - version: 5.0.0 + specifier: 5.0.1 + version: 5.0.1 lucide-react: specifier: 0.552.0 version: 0.552.0(react@19.2.6) @@ -13758,8 +13758,8 @@ packages: canvas: optional: true - linkify-it@5.0.0: - resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + linkify-it@5.0.1: + resolution: {integrity: sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==} listr2@10.2.1: resolution: {integrity: sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==} @@ -30874,7 +30874,7 @@ snapshots: htmlparser2: 10.1.0 uhyphen: 0.2.0 - linkify-it@5.0.0: + linkify-it@5.0.1: dependencies: uc.micro: 2.1.0