Skip to content

Context-aware escaping #181

Open
Open

Description

@quasicomputational

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: &quot;Hello!&quot; } - 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.

Activity

  1. lambda-fairy commented on Mar 7, 2020

    @lambda-fairy
    Owner

    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:

  2. changed the title [-]Escaping in <style> and <script> is strictly wrong[/-] [+]Context-aware escaping[/+] on Apr 24, 2021
  3. lambda-fairy commented on Apr 24, 2021

    @lambda-fairy
    Owner

    Some notes before I forget:

    • 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.
        • See https://stackoverflow.com/q/9320427/617159
        • 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 😏
  4. added
    context aware escapingThis feature depends on Maud treating certain elements and attributes in a special way
    on Jan 6, 2025
  5. CJ-Jackson commented on Aug 7, 2025

    @CJ-Jackson

    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.

  6. tv42 commented on Feb 10, 2026

    @tv42

    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.

  7. NfNitLoop commented on Oct 22, 2026

    @NfNitLoop

    At minimum, we need [...]

    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.:

    • 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.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugcontext aware escapingThis feature depends on Maud treating certain elements and attributes in a special wayhardneeds design

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions