30 秒看懂
Theo Browne 回顾自己对 Markdown 的喜爱,并解读 Brock 对其语法和扩展机制的批评。他讨论解析器漏洞、内联 HTML、引用解析和替代方案,强调格式的便利与完整处理流程的复杂度之间存在权衡。
- 1易读的源文件Markdown 让简单文档容易以文本形式编写和分享。
- 2多种等效形式不同标题和强调写法增加了实现需要处理的情况。
- 3解析器安全markdown-it 漏洞公告涉及特定受影响版本,而非所有 Markdown 解析器。
- 4文档级引用后面的定义可以决定前面的文本是否成为引用式链接。
- 5提出的替代方向作者提出使用明确规范的标记格式、显式扩展和构建系统。
要点建议
- Markdown 适合简单文本,但等效写法和扩展会使渲染复杂化。
- 内联 HTML 和可执行扩展需要明确的信任与安全决策。
- CommonMark 引用式链接可以依赖其他位置的定义;脚注则是扩展。
- 不能把特定解析器版本的漏洞推广到所有实现。
- 应根据所需功能、处理方式和安全边界选择文档工具。
按章节阅读整理后的全文
为什么重新审视 Markdown?
Theo 解释自己为何采用 Markdown,以及用途扩张为何引出新问题。
我推崇 Markdown 已经很多年。过去我把简历以 Markdown 放在 GitHub 上,甚至放弃过一些不接受这种格式的申请。它的吸引力在于:源文件简单易读,不需要复杂工具就能生成排版漂亮的文档。
我感谢 John Gruber 和 Aaron Swartz 创造了 Markdown。大学时尝试 LaTeX 遇到不少困难,后来 Markdown 对我来说一下子变得顺手,也成为我写作的默认格式。正因如此,一篇追问我们为什么还在使用 Markdown 的文章吸引了我。
Markdown 的用途已经超出简单文档。我们嵌入其他格式、添加扩展,也越来越多地用它与语言模型和代理交流。我想问的是:原本的格式在哪些地方很好用,而新的需求又在哪里带来了摩擦?
写起来简单,解析起来复杂
文章对比易上手的语法、多种等效写法和解析器边缘情况。
我读的是 Brock 的文章《Why the heck are we still using Markdown?》:https://bgslabs.org/blog/why-are-we-using-markdown/。作者主要讨论 CommonMark,认为一种原本追求简单的格式积累了复杂语法和过多期待。我认同其中很多不满,尽管自己每天仍在使用它。
Markdown 的优点是真实存在的:基础写法容易上手,纯文本也能读懂,标题、强调和链接都很方便。CommonMark 为实现提供了一份详细的共同规范。普通作者无需学完整套解析规则,也能很快得到有用的输出。

问题从多种写法产生相同结果时开始。文章展示了一个用井号写的标题和另一个用下划线形式写的标题;强调文本也可以在星号和下划线之间切换。这些选择方便了作者,却给工具带来了更多需要处理的情况。
嵌套的强调语法甚至在实现解析器之前就可能变得难以阅读。我们在 T3 Chat 遇到过许多奇怪的渲染情况,尤其是处理生成内容时。因此,看似简单的格式,可能给必须接受所有有效写法的软件带来相当大的复杂度。
文章提到了 markdown-it 的一个正则表达式拒绝服务漏洞。这是特定受影响版本和代码路径中的缺陷,并不证明每个 Markdown 解析器都有漏洞。公告列出的受影响范围是 13.0.0 起至 14.1.1 之前,14.1.1 包含修复:https://github.com/advisories/GHSA-38c4-r59v-3vqw。
内联 HTML 与扩展
混合格式增加能力,也增加复杂度;安全取决于具体实现和信任边界。
作者把 Markdown 中的内联 HTML 比作加入一个强大的逃生口。它让作者使用基础语法无法表达的元素和属性,但渲染流程也因此需要决定如何处理两种语法及其相互作用。灵活性是有代价的。

我自己也感受过这个问题。一位朋友曾试图让同一份字节既作为 GitHub 个人主页的 Markdown 文件,又作为 HTML 首页;让两个渲染环境结果一致非常费劲。Markdown 能包含部分 HTML,并不意味着所有渲染器都会以相同方式处理混合文档。
作者常常需要的不止是标题和段落:还有嵌入媒体、图表、数学公式、脚注、引用、样式或交互组件。每增加一种能力,就要对语法、依赖和信任边界作选择。一种原本轻量的文本格式逐渐变得像文档处理系统。
我查看了自己的博客,很快就发现了 iframe,以及放在 Markdown 链接里的 HTML 图片。重点不是这些具体片段天然不安全,而是实际发布需求会把我们推离最简单的 Markdown 示例,进入混合格式工作流。

允许原始 HTML、插件或可执行扩展会改变安全模型。内容不可信时,应用需要适当的清理和安全边界;解析器本身不能替代完整的安全策略。不同实现和配置所承担的风险也不同。
历史语法与引用
Theo 讨论多种语法形式和文档级引用解析。脚注是 CommonMark 扩展,而非核心语法。
Markdown 借鉴了纯文本邮件和网络讨论中的习惯。这段历史留下了多种表达类似结构的方式:标题样式、列表标记、分隔线和强调定界符。熟悉的写法便于使用,但重叠和变化也让边缘情况更难推理。
有序列表也是一个例子:作者可以重复使用数字标记,让渲染器生成显示出来的顺序。调整条目时这很方便,但文件中的文字与最终输出并不总是一一对应。
文章展示了一个引用:它如何被解释取决于文档其他地方是否有对应定义。CommonMark 支持引用式链接;脚注属于扩展,而不是 CommonMark 核心功能。渲染器可能需要文档级引用表或多次处理才能解析这些链接。

作者用形式语言术语描述这种依赖,认为 Markdown 比简单的局部替换复杂。实际现象很明确:后面的定义可以影响前面的引用。至于形式分类,那是作者的论证,不能仅凭展示的例子就视为已证明。
替代方案与权衡
提出的构建系统与受控扩展可以使格式用途更清晰,但每种选择仍有复杂度和安全决策。
如果再添加脚注、自定义提示块、数学公式和样式,处理流程会进一步增长。知识管理系统可能需要插件、排版库以及样式隔离方式。选择格式时要考虑整个处理链,而不只是作者输入的字符。
我喜欢 Notion 对 Markdown 语法的另一种用法:输入井号和空格可以把块变成标题。在这里,熟悉的语法更像编辑器快捷操作。这与把整篇文档存储并渲染为 Markdown 是不同用途,导出也可能有自己的局限。
作者考虑了纯文本、reStructuredText 和 MDX,但认为每种方案都有权衡。他提出的替代方向是:采用规范清楚的标记格式、构建系统、明确的短代码和受控钩子,取代不受限制的内联 HTML。这是一项设计提议,并非已被证明适用于所有场景的现成替代品。
构建系统和钩子可以让扩展点更明确,但它们也会引入自己的复杂度和安全决策。关键问题是文档实际需要哪些功能,以及处理过程中哪些代码可以被信任执行。更简洁的语法本身不能保证任意扩展安全。
文章还涉及形式语言理论和编程语言的定义。这些区分取决于讨论的具体语言和计算模型;一段有趣的 Markdown 论辩,不应被当作 Markdown 本身具有图灵完备性的证明。
人们对 Markdown 歧义和实现错误的抱怨已有很长历史,也曾呼吁制定更清楚的标准。CommonMark 是对这段历史的一种回应。标准化行为可以提高一致性,但仍不能自动回答:这些行为对某个应用是否好用、是否合适。
这篇文章让我意识到,自己每天使用的一种格式包含了多少习以为常的复杂度。我不是建议大家立刻重写所有文档。我希望我们认识到其中的权衡:Markdown 适合简单文本,但扩展、混合 HTML 和渲染需求可能让周边系统难得多。
我也有冲动发明一种新的标记语言,但冲动本身并不是解决方案。首先要确定需要表达什么、文档如何处理,以及哪些安全边界重要;然后再根据这些需求选择或设计工具。
同频道的其他文章
38:47EN → 简体中文
36:07EN → 简体中文
30:37EN → 简体中文
0:43EN → 简体中文
29:22EN → 简体中文
31:13EN → 简体中文