7.7 Enabling Unsafe HTML in Goldmark
Right, let’s talk about letting Hugo get its hands dirty with raw HTML. By default, Goldmark, Hugo’s Markdown processor, is a bit of a neat freak. It sees your <div> or <script> tag and immediately sanitizes it into oblivion. This is, generally speaking, a fantastic idea. It prevents a whole universe of cross-site scripting (XSS) attacks and keeps your site from accidentally turning into a mess of malformed tags.
But sometimes, you need that control. Maybe you’re embedding a complex interactive chart from a third party, or you’ve built a custom CSS widget that just needs a specific HTML structure. This is where the ominously named unsafe setting comes in. Don’t let the name scare you; it’s not inherently evil. It’s just Hugo being very clear with you: “You’re turning off the safety rails. Don’t blame me if you drive off the cliff.”
How to Enable the “Unsafe” Option
You don’t enable this in your Markdown. You do it in your site-wide configuration. Open up your hugo.toml (or config.toml/hugo.yaml/hugo.json – you get the idea) and look for the [markup.goldmark] section. You need to drill down into the renderer’s security settings.
Here’s how you’d set it in TOML:
[markup]
[markup.goldmark]
[markup.goldmark.renderer]
unsafe = true
And here’s the equivalent in YAML:
markup:
goldmark:
renderer:
unsafe: true
The key here is the hierarchy: markup.goldmark.renderer.unsafe. Set this to true, restart your Hugo server (because this isn’t a setting that’s hot-reloaded, sadly), and suddenly your HTML tags will pass right through Goldmark untouched.
What “Unsafe” Actually Allows (And What It Doesn’t)
Enabling unsafe doesn’t turn Goldmark into a free-for-all. It’s more precise than that. All it does is tell Goldmark’s HTML renderer to stop skipping raw HTML blocks it finds in your Markdown. The parsing and processing of Markdown itself remain identical.
So, this Markdown:
This is a paragraph.
<div style="background: #ffcccc; padding: 1em;">
This is a **div element**. Notice the Markdown inside it *doesn't* get processed.
</div>
Another paragraph.
Will now render exactly as you’d hope (or fear). The <div> will appear in your final HTML output. Crucially, the **strong** text inside the div will not be converted to <strong>strong</strong> because Goldmark doesn’t parse Markdown inside raw HTML blocks. This is a common gotcha. You’re mixing two languages, and the parser doesn’t recursively parse the HTML.
The Right Way to Mix Markdown and HTML
Ah, but what if you need Markdown inside that HTML block? Hugo has you covered with a special extension that is, frankly, black magic. You can use the markdown attribute on a block-level HTML element.
<div style="background: #eeeeff; padding: 1em;" markdown="1">
This is **inside** the div. Now the Markdown *will* be processed.
</div>
That markdown="1" attribute is a signal to Goldmark to parse the contents of that specific element as Markdown. It’s the best of both worlds. You get the structural control of HTML and the writing simplicity of Markdown inside it. Just remember this only works for block-level elements like <div>, <section>, <p>, etc., not inline ones like <span>.
Best Practices and the “Unsafe” Reality
Don’t Do This Globally Without a Reason: If you only need raw HTML in one section of one page, consider using Hugo’s shortcodes instead. They’re a safer, more controlled way to inject custom HTML. Only enable
unsafeglobally if you’re constantly bumping into the limitation.You Are Now the Security Filter: With
unsafeenabled, if you input user-generated content, you are 100% responsible for sanitizing it. Hugo has handed you the keys and washed its hands of the problem. A single mischievous<script>tag in a comment could own your site.It’s Not a Performance Hit: Enabling this setting doesn’t make Hugo slower. It just removes a single check in the rendering process. The real cost is in the cognitive load of ensuring your output is correct and secure.
So, use unsafe, but use it like a skilled artisan uses a sharp chisel: with respect, purpose, and the understanding that you’re the one controlling the tool, not the other way around.