👮Security and Escaping

Corgi follows the same security model Go's built-in html/template template engine does. That means, it can contextually escape HTML, CSS, JS, and URL and srcset attributes using the same strategy to determine the type of an attribute. Additionally, corgi also correctly contextually escapes htmx attributes.

Just like Go's engine, corgi assumes that template authors are trusted, but expressions are not.

You can also use pre-escaped expressions by using the types provided in corgi's woof package.

HTML

Corgi automatically escapes all HTML you write to prevent you from accidentally closing or opening a tag or prematurely ending an attribute.

p(foo=`bar"`) This <p> will be escaped.

JavaScript

Corgi prints text in script elements verbatim, only escaping </script> to <\/script> to prevent accidental closing of the script element in strings.

String text in JS attributes will have quotes escaped.

Expressions aof type woof.JS are printed verbatim. Expressions of type woof.JSStr are printed verbatim inside double quotes (with quotes escaped in JS attributes). All other expressions are printed as JSON values.

-
  c := struct{
      A string
      B struct{C int}
    }{
      A: "foo",
      B: struct{C int}{C: 123},
    }
script.
  let a = #{123};
  let b = #{"abc\n"};
  let c = #{c};

button(onclick="f(#{123})")
button(onclick="f(#{"abc\n"})")
button(onclick="f(#{c})")

CSS

Just like inside script elements, text inside style elements is also printed verbatim, only escaping </style> to <\/style> to prevent accidental closing of the script element in strings.

When writing expressions, the value is escaped/filtered using woof.FilterCSS unless it is of type woof.CSS.

URLs

Like any other attribute, attributes containing URLs will always have quotes escaped.

Additionally, corgi filters out URLs with interpolated protocols/expressions with protocols other than http, https, tel, or mailto.

String text is normalized, keeping valid percent escapes, but percent escaping runes that haven't yet been.

Expressions before the start of queries are also just normalized, after the start of queries expressions will be escaped so that they form a valid URL query parameter value.

- searchEngine := "google.com/search"
  q := corgis <3
a(href="https://#{searchEngine}?q=#{q}") Search Google
- danger := "ftp://foo.com"
a(href=danger) Don't click me!

Srcset

URLs in srcset attributes are escaped using the same strategy as URL attributes.

Last updated