You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The HTML spec defines <style> and <script> as 'raw text elements', meaning that escapes in their bodies are not processed (hence, e.g., span:before { content: "Hello!" } cannot be escaped to span:before { content: "Hello!" } - try it in a browser if you don't believe me).
This is a potential footgun with maud: the path of less resistance, letting maud do the escaping, means that the scripts and styles get mangled; however, naively using PreEscaped could theoretically introduce an XSS vulnerability because then there's no check for an errant </.
This is related to #88. I'm afraid that the HTML syntax is so complicated that there's no way to avoid a certain amount of context-awareness here. I don't know what the ideal API looks like, or even if maud can do much better, but at the very least the docs should point out the footgun here.
Yeah, I've come around to accepting that this is an issue. We can make some simplifications, as e.g. the lack of legacy code allows us to simply reject cases we don't understand. But overall this will need a lot of design work.
As a prerequisite, we want to validate elements / attributes and throw a hard error when either is unknown. This is because new features are added to HTML all the time, and we can't predict how escaping will work for them.
This would imply some configuration (?) for custom elements. Maybe look at how Clippy does config.
At minimum, we need: ToHtml/ToAttr, ToText (for <title> and <textarea>), ToUrl (for href and <img src>), ToTrustedUrl (for <script src>), ToStyle/ToStyleAttr, ToScript/ToScriptAttr.
Consider whether we need separate traits for "element body" and "attribute value" contexts, or we can get away with one trait for both.
Separate traits let us micro-optimize, as e.g. element bodies don't need to escape quotes.
Is the Url / TrustedUrl distinction necessary? Go templates don't do it.
Consider serde integration for safely embedding JSON.
It is possible to embed JSON in JavaScript safely, but I'd rather not encourage it. I'd prefer either <script type="application/json"> or the <data> element instead.
It's a bit annoying that <data> puts its payload in an attribute, given that both Maud and JSON use double quotes. If people complain, we might need a ToSingleQuotedAttr category 😏
I believe many have got used to not having context aware escaping, considering it a security risk, I think it might be a great idea to have that feature behind a feature flag.
I think a good approach might be to set up tests where a string is put into each of the possible contexts, and then the generated HTML is parsed with https://crates.io/crates/html5ever and the string extracted and compared to original; then let a fuzzer pick the strings for each of the tests.
At first glance, seeing maud's syntax, I only expected that it would contextually escape what it can easily glean from its own syntax. i.e.:
Text appearing in attribute position is escaped for attributes.
Text appearing outside/inside tags is html-escaped.
And:
The user can opt out of that by wrapping with the PreEscaped type.
I wouldn't expect html! to know about <script> vs. <style> quoting. If I'm putting anything in there, I'll just add it as PreEscaped text. Yes, that "could theoretically introduce an XSS vulnerability", but IMO web developers should probably know better than injecting untrusted code into your CSS or JS. (And you can be generous and document that pitfall on PreEscaped, too.)
Activity
lambda-fairy commentedon Mar 7, 2020
Sorry about the delay.
Yeah, I've come around to accepting that this is an issue. We can make some simplifications, as e.g. the lack of legacy code allows us to simply reject cases we don't understand. But overall this will need a lot of design work.
Relevant links:
html/template[-]Escaping in <style> and <script> is strictly wrong[/-][+]Context-aware escaping[/+]lambda-fairy commentedon Apr 24, 2021
Some notes before I forget:
ToHtml/ToAttr,ToText(for<title>and<textarea>),ToUrl(forhrefand<img src>),ToTrustedUrl(for<script src>),ToStyle/ToStyleAttr,ToScript/ToScriptAttr.Url/TrustedUrldistinction necessary? Go templates don't do it.serdeintegration for safely embedding JSON.<script type="application/json">or the<data>element instead.<data>puts its payload in an attribute, given that both Maud and JSON use double quotes. If people complain, we might need aToSingleQuotedAttrcategory 😏CJ-Jackson commentedon Aug 7, 2025
I believe many have got used to not having context aware escaping, considering it a security risk, I think it might be a great idea to have that feature behind a feature flag.
tv42 commentedon Feb 10, 2026
Instead of Go html/template, you should be looking at https://github.com/google/safehtml
https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/42934.pdf contains some examples.
I think a good approach might be to set up tests where a string is put into each of the possible contexts, and then the generated HTML is parsed with https://crates.io/crates/html5ever and the string extracted and compared to original; then let a fuzzer pick the strings for each of the tests.
NfNitLoop commentedon Oct 22, 2026
FWIW, I'd settle for a lot less than that!
At first glance, seeing maud's syntax, I only expected that it would contextually escape what it can easily glean from its own syntax. i.e.:
And:
I wouldn't expect
html!to know about<script>vs.<style>quoting. If I'm putting anything in there, I'll just add it as PreEscaped text. Yes, that "could theoretically introduce an XSS vulnerability", but IMO web developers should probably know better than injecting untrusted code into your CSS or JS. (And you can be generous and document that pitfall on PreEscaped, too.)