diff --git a/gateway/platforms/wecom_callback.py b/gateway/platforms/wecom_callback.py index e08bc039742..b656d2ecf96 100644 --- a/gateway/platforms/wecom_callback.py +++ b/gateway/platforms/wecom_callback.py @@ -17,7 +17,11 @@ import logging import socket as _socket import time from typing import Any, Dict, List, Optional -from xml.etree import ElementTree as ET +# Security: parse untrusted, pre-auth request bodies (WeCom callbacks) with +# defusedxml to block billion-laughs / entity-expansion (and XXE) DoS. The +# parsing API (fromstring) is a drop-in for the stdlib calls used below; +# response-building XML lives in wecom_crypto.py and is not parsed here. +import defusedxml.ElementTree as ET try: from aiohttp import web diff --git a/web/src/components/Markdown.tsx b/web/src/components/Markdown.tsx index bef0804e7c4..a78c4430c34 100644 --- a/web/src/components/Markdown.tsx +++ b/web/src/components/Markdown.tsx @@ -324,11 +324,24 @@ function InlineContent({ ); - case "link": + case "link": { + // Security: only render http(s)/mailto links. Other schemes + // (javascript:, data:, vbscript:) are dropped to plain text so a + // crafted link in agent/message content can't execute on click. + const href = node.href.trim(); + if (!/^(https?:|mailto:)/i.test(href)) { + return ( + + ); + } return ( ); + } case "br": return
; }