Why Markdown Strips Raw HTML (and What to Use Instead)
Quick answer
CommonMark doesn't strip raw HTML. By default, the base spec passes inline tags and HTML blocks straight through into the rendered output, unescaped. What people usually mean when they say "Markdown strips HTML" is a choice a specific renderer makes on top of that — most visibly, GitHub Flavored Markdown's Disallowed Raw HTML extension. Below: what the spec actually says, why GitHub added that extension, and the Markdown-native syntax that covers most reasons you'd reach for HTML in the first place.
How it actually works
CommonMark passes raw HTML through by default
The CommonMark spec defines seven types of HTML blocks — <pre>, <script>, and <style> tags, HTML comments, generic block-level tags like <div> or <table> — plus inline HTML for anything shorter. All of it counts as raw HTML and "will not be escaped in HTML output." The spec isn't shy about this either; it leaves sanitization entirely up to whoever builds the renderer. Ever pasted a stray <div> into a Markdown file and watched it render as an actual div instead of literal text? That's CommonMark working exactly as specified.
GFM's Disallowed Raw HTML extension
GitHub Flavored Markdown builds on top of that default rather than around it. GFM's spec documents a "Disallowed Raw HTML" extension — informally called tagfilter — applied as a post-processing step after Markdown converts to HTML, specifically for security and consistency on github.com. It's narrower than blocking HTML outright. The extension neutralizes a defined set of higher-risk tags while leaving the rest of CommonMark's raw-HTML handling intact underneath, including the quirk where the same Markdown file renders differently across parsers.
Why GitHub formalized this at all
Before GFM had a written spec, GitHub's engineering team noted that "very similar looking Markdown documents can be rendered as wildly different outputs depending on your Markdown parser of choice." Naming the disallowed-raw-HTML behavior explicitly closed part of that gap. It's the same motivation behind GFM's other formally documented extensions: tables, task lists, strikethrough, and the autolink extension that turns a bare URL into a clickable link without any HTML <a> tag at all.
When to use it (and when to skip it)
If your renderer happens to allow raw HTML, it's tempting to drop in a <div> for a layout tweak or a <br> for a forced line break. Most of that isn't necessary. GFM already has Markdown-native syntax for the common cases — tables, strikethrough, and task lists are all built in, and a trailing double-space (or a blank line, for a full paragraph break) covers what people usually reach for <br> to do.
For callouts, skip the hand-rolled <div class="note"> and use GitHub's NOTE, TIP, and WARNING alert syntax instead — it renders consistently and stays plain text underneath. This is really the same argument as why writers choose plain text over rich text in general: every dependency on a specific renderer's HTML handling is one more thing that breaks when the file moves somewhere else.
If your Markdown includes any user-submitted content, treat this as a security question, not a style one. A CommonMark community discussion on rendering user content safely doesn't mince words about it: a parser's disable-HTML flag isn't a complete security boundary on its own. The attack surface extends past raw tags into things like javascript: and data: URIs, and different parsers handle edge cases inconsistently. The recommended move is to sanitize the rendered HTML output with a tool built for that job — not to trust one flag and stop there.
There's still an exception worth keeping: a rare layout need, in a renderer you control, where the file will only ever render in that one place. That's a deliberate trade-off. It shouldn't be the default you reach for out of habit.
Doing this with Carets
Carets forbids raw HTML in the editor entirely. Every note and every code file stays plain Markdown, not an HTML sandbox with Markdown syntax bolted on top. That's a deliberate fit for how Carets works: your files stay plain text, portable and future-proof, so a README or a set of notes reads the same way whether you open it in Carets, on GitHub, or in a plain text editor a year from now.
It also keeps the app fast and predictable instead of asking it to be a partial browser. Carets brings Markdown, plain text, and code into one native editor for iPhone, iPad, and Mac, with syntax highlighting for code and config files and everything organized into files, projects, and tags — structure without an HTML escape hatch. Get Carets on the App Store for iPhone, iPad, and Mac.
Frequently Asked Questions
Does Markdown always strip raw HTML?
No. CommonMark, the base spec, allows raw HTML to pass through into the rendered output unescaped by default. Stripping is a choice a specific renderer makes on top of that, usually for security. GitHub Flavored Markdown, for example, layers a Disallowed Raw HTML extension on top of CommonMark's default passthrough behavior.
What is GFM's Disallowed Raw HTML extension?
It's a post-processing step GitHub applies after converting Markdown to HTML, informally called tagfilter. Rather than blocking every HTML tag, it neutralizes a specific set of higher-risk tags while leaving CommonMark's normal raw-HTML block and inline handling in place underneath.
Is disabling raw HTML in a Markdown parser enough to stop XSS?
Not on its own. Security discussion in the CommonMark community points out that attack surface extends beyond raw tags to things like javascript: and data: URIs and attribute injection, and that different parsers handle edge cases inconsistently. The recommended approach is to sanitize the rendered HTML output with a tool built for that job, not to rely on a single disable-HTML flag.
What should I use instead of raw HTML in Markdown?
For the most common reasons people reach for HTML — tables, strikethrough, task lists, a forced line break — GFM already has native Markdown syntax that does the job without dropping into HTML at all. Reserve raw HTML, if your renderer allows it, for the rare case with no Markdown equivalent.
Why does Carets forbid raw HTML in the editor entirely?
Carets renders Markdown as Markdown, not as an HTML sandbox. Keeping raw HTML out of the body means every note and README stays plain text you can read, diff, and move between tools without carrying rendering assumptions that only work in one place.
Conclusion
"Markdown strips raw HTML" is shorthand for a renderer choice layered on top of a spec that allows it by default. CommonMark passes HTML through; GFM names the parts it filters out and explains why. Either way, the practical takeaway holds: reach for GFM's native syntax first, and treat raw HTML — where your renderer even allows it — as the exception, not the default.