diff --git a/src/app/components/math/KaTeX.tsx b/src/app/components/math/KaTeX.tsx
index ebaf17e7d..26d27cd68 100644
--- a/src/app/components/math/KaTeX.tsx
+++ b/src/app/components/math/KaTeX.tsx
@@ -21,12 +21,31 @@ type KaTeXProps = {
* inline (in its error colour) rather than throwing. The HTML returned by
* `renderToString` is produced by our own trusted call from a fixed options
* object — it is safe to inject via `dangerouslySetInnerHTML`.
+ *
+ * `maxSize`/`maxExpand` cap how large a single glyph (`\\rule`, etc.) or macro
+ * expansion remote LaTeX can request, and `trust: false` disables commands
+ * that can embed arbitrary HTML/URLs (e.g. `\\includegraphics`, `\\href`) —
+ * without these a hostile `$$...$$` from a remote message can DoS or (via
+ * `trust`) inject unsafe links (Gitea #65). `strict: 'ignore'` keeps unknown-
+ * but-harmless LaTeX from spamming the console as before. Extremely long
+ * source is rendered as plain text rather than handed to KaTeX at all.
*/
+const MAX_LATEX_LENGTH = 5000;
+
export default function KaTeX({ latex, displayMode = false }: KaTeXProps) {
+ if (latex.length > MAX_LATEX_LENGTH) {
+ const Plain = displayMode ? 'div' : 'span';
+ return {latex};
+ }
+
const html = katex.renderToString(latex, {
displayMode,
throwOnError: false,
output: 'htmlAndMathml',
+ maxSize: 10,
+ maxExpand: 100,
+ trust: false,
+ strict: 'ignore',
});
const Wrapper = displayMode ? 'div' : 'span';
@@ -34,7 +53,7 @@ export default function KaTeX({ latex, displayMode = false }: KaTeXProps) {
return (
);