Avoid string variable escaping?

Hi,

I have a string variable $v with the value a and the template {{ $v }} outputs a

This doesn’t happen if a is directly in the template as html and not in a variable, so I guess there’s some kind of escaping going on when evaluating the variables.

Is there a way to avoid this behavior?

Thanks!

1 Like

Try
{{ $v | safeHTML }}

Thanks. I tried it but it doesn’t work when inside a href attribute: <a href='{{ $v | safeHTML }}'>{{ $v | safeHTML }}</a> outputs <a href='&amp;#97;'>&#97;</a>

Also tried with safeHTMLAttr with the same result.

Would htmlUnescape work?

kind of (it works for this minimal example).

I have an obfuscated email address in a param and it always ends escaped no matter what I try. The only solution I found is hardcoding it in the template.

It seems like the template is post processing its dynamic content.

So it would help to update your minimal example to use a fake email or something that obfuscates to a string that doesn’t work with above suggested solutions.

Sure. The encoded address is foo@bar.com. The following template:

  {{ $href := "m&#97;i&#108;to&#58;f&#37;6Fo&#64;&#98;ar&#46;com" }}
  {{ $address := "&#102;oo&#64;ba&#114;&#46;co&#109;"}}
  <div id="variables">
    <a href="{{ $href }}">{{ $address }}</a>
  </div>
  <div id="variables-htmlUnescape ">
    <a href="{{ $href | htmlUnescape }}">{{ $address | htmlUnescape }}</a>
  </div>
  <div id="variables-safeHTML ">
    <a href="{{ $href | safeHTML }}">{{ $address | safeHTML }}</a>
  </div>
  <div id="variables-safeHTMLAttr ">
    <a href="{{ $href | safeHTMLAttr }}">{{ $address | safeHTMLAttr }}</a>
  </div>
  <div id="variables-html ">
    <a href="{{ $href | html }}">{{ $address | html }}</a>
  </div>
  <div id="hardcoded">
    <a href="m&#97;i&#108;to&#58;f&#37;6Fo&#64;&#98;ar&#46;com">&#102;oo&#64;ba&#114;&#46;co&#109;</a>
  </div>

Generates:

  <div id="variables">
    <a href="m&amp;#97;i&amp;#108;to&amp;#58;f&amp;#37;6Fo&amp;#64;&amp;#98;ar&amp;#46;com">&amp;#102;oo&amp;#64;ba&amp;#114;&amp;#46;co&amp;#109;</a>
  </div>
  <div id="variables-htmlUnescape ">
    <a href="mailto:f%6Fo@bar.com">foo@bar.com</a>
  </div>
  <div id="variables-safeHTML ">
    <a href="m&amp;#97;i&amp;#108;to&amp;#58;f&amp;#37;6Fo&amp;#64;&amp;#98;ar&amp;#46;com">&#102;oo&#64;ba&#114;&#46;co&#109;</a>
  </div>
  <div id="variables-safeHTMLAttr ">
    <a href="m&amp;#97;i&amp;#108;to&amp;#58;f&amp;#37;6Fo&amp;#64;&amp;#98;ar&amp;#46;com">&amp;#102;oo&amp;#64;ba&amp;#114;&amp;#46;co&amp;#109;</a>
  </div>
  <div id="variables-html ">
    <a href="m&amp;#97;i&amp;#108;to&amp;#58;f&amp;#37;6Fo&amp;#64;&amp;#98;ar&amp;#46;com">&amp;#102;oo&amp;#64;ba&amp;#114;&amp;#46;co&amp;#109;</a>
  </div>
  <div id="hardcoded">
    <a href="m&#97;i&#108;to&#58;f&#37;6Fo&#64;&#98;ar&#46;com">&#102;oo&#64;ba&#114;&#46;co&#109;</a>
  </div>

The desired output is in the “hardcoded” div (the values are the same as the declared). I can get it to work for the address, but the href is being treated differently and always gets escaped. I even tried using the $href as the content of the <a> element instead of the href attribute and the output is different:

  <div id="href-safeHTML ">
    <a href="{{ $href | safeHTML }}">{{ $href | safeHTML }}</a>
  </div>

Results in:

  <div id="href-safeHTML ">
    <a href="m&amp;#97;i&amp;#108;to&amp;#58;f&amp;#37;6Fo&amp;#64;&amp;#98;ar&amp;#46;com">m&#97;i&#108;to&#58;f&#37;6Fo&#64;&#98;ar&#46;com</a>
  </div>

I don’t understand… this:

{{ $href := "mailto:foo@bar.com" }}
    {{ $address := "foo@bar.com"}}
    <div id="variables-htmlUnescape ">
        <a href="{{ $href | htmlUnescape }}">{{ $address | htmlUnescape }}</a>
    </div>

gives:

<div id="variables-htmlUnescape ">
        <a href="mailto:foo@bar.com">foo@bar.com</a>
    </div>

Seems to work fine… So do you want to escape each and every letter as in your hardcoded div?

It works in the sense that the resulting email is valid but misses the point of obfuscation.

What I want is the values preserved as in the “hardcoded” div but without hardcoding them.

I read a bit about go html/template package and it escaping the content contextually, trusting the template and not trusting the dynamic content. About href, taken from template package - html/template - Go Packages :

This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing functions to each simple action pipeline, so given the excerpt

<a href="/search?q={{.}}">{{.}}</a>
At parse time each {{.}} is overwritten to add escaping functions as necessary. In this case it becomes

<a href="/search?q={{. | urlescaper | attrescaper}}">{{. | htmlescaper}}</a>
where urlescaper, attrescaper, and htmlescaper are aliases for internal escaping functions.

I tried to bypass it without success (sorry for my go, I’m new to it): Go Playground - The Go Programming Language

Maybe @bep knows a way to bypass the escaping?

Reviving for the sake of documenting a solution.

@butaca you’re absolutely spot on regarding the contextual awareness of html/template. That’s one of the features that makes it great!

Here’s how you can bypass it for an arbitrary HTML attribute:

Template

{{ $v := "&#97;" }}
<a {{ printf "href=%q" $v | safeHTMLAttr }}>{{ $v | safeHTML }}</a>

Output

<a href="&#97;">&#97;</a>

Note that whenever you use the safe* functions ( safeHTML , safeHTMLAttr , etc), it means you fully trust the input.

A malicious input could infect your website. Compare what happens when you mark unsafe values as safe:

Template

{{ $v := "\"><script>alert('hello')</script>" }}
<p>Safe: <a {{ printf "href=%q" $v }}>{{ $v }}</a></p>
<p>Unsafe use of safe*: <a {{ printf "href=%q" $v | safeHTMLAttr }}>{{ $v | safeHTML }}</a></p>

Output

<p>Safe: <a ZgotmplZ>&#34;&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;</a></p>
<p>Unsafe use of safe*: <a href="\"><script>alert('hello')</script>">"><script>alert('hello')</script></a></p>
3 Likes