From 2baf2d4e2c1d8d059a0795bf46596c64c28e01e5 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 20 Aug 2026 18:19:31 +0200 Subject: fix(compose): document what actually suppresses raw HTML, item 123 CMARK_OPT_SAFE has had no effect since cmark-gfm made safe mode the default; the flag is retained for API compatibility and the real protection is that CMARK_OPT_UNSAFE is never set. Measured against 0.29.0.gfm.13: rendering with OPT_DEFAULT alone, with OPT_SAFE, and with OPT_UNSAFE shows the first two suppress a script element and a javascript: link while the third leaks both. The comment credited the flag, which would have sent the next reader to the wrong place, and the test could not tell the two apart: it would have passed just as well with the flag deleted. What it has to guard against is OPT_UNSAFE being introduced, so it now also asserts that unsafe links are stripped, which is a protection this gets for free and previously asserted nothing about. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015muoUo2GdxmBDSp5vjYcbE --- src/markdownrenderer.cpp | 21 +++++++++++++++++---- tests/test_markdownrenderer.cpp | 29 ++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/markdownrenderer.cpp b/src/markdownrenderer.cpp index a9b8177..ccb3309 100644 --- a/src/markdownrenderer.cpp +++ b/src/markdownrenderer.cpp @@ -34,8 +34,8 @@ namespace { /// /// `table` is absent deliberately, not by oversight: tables render badly /// across mail clients regardless of who generates them. `tagfilter` is absent -/// because CMARK_OPT_SAFE already suppresses raw HTML wholesale, which is the -/// stronger measure. +/// because safe mode (see below) already suppresses raw HTML wholesale, which +/// is the stronger measure. const char *const kExtensions[] = { "autolink", "strikethrough", "tasklist" }; } // namespace @@ -51,8 +51,21 @@ QString MarkdownRenderer::toHtml(const QString &markdown) // after the first call. cmark_gfm_core_extensions_ensure_registered(); - // SAFE suppresses raw HTML in the INPUT. It does not escape the output, - // which is markup by definition. + // CMARK_OPT_DEFAULT is 0, and CMARK_OPT_SAFE is a NO-OP in cmark-gfm 0.29: + // safe mode has been the default since that release, and the flag is kept + // only for API compatibility with code written against older versions. + // The real requirement is that CMARK_OPT_UNSAFE must never be set. Under + // safe mode a raw \n\nafter")); QVERIFY2(!html.contains(QStringLiteral("