Posted by

Escape Output Safely in HubSpot CMS: Using HubL escape, escapejs, urlencode and tojson

Every HubL template eventually prints a value that someone else controls: a URL parameter, a text field filled in by an editor, a HubDB cell, a form value. If that value lands in your page unescaped, a stray quote or a <script> tag can break your layout or open a cross-site scripting (XSS) hole. This guide shows which HubL filter to use in each place a value can end up.

The rule: escape for the context, not for the variable

The same string needs different treatment depending on where you print it. A value inside HTML text, inside an attribute, inside a URL and inside a JavaScript block each have different dangerous characters. Pick the filter that matches the destination.

Where the value goesFilter
HTML text and quoted attributesescape
Part of a URL (query string value)urlencode
Inside a quoted JavaScript stringescapejs
Passing a whole value or object to JavaScripttojson
Plain-text excerpt of HTMLstriptags then truncate

1. HTML text and attributes: escape

The escape filter converts characters such as <, >, & and quotes into HTML entities, so the browser shows them as text instead of treating them as markup.

{% set campaign = request.query_dict.campaign %}

<p>Campaign: {{ campaign|escape }}</p>

<a href="/offers" title="{{ campaign|escape }}">See offers</a>

Always keep attribute values in quotes. An unquoted attribute can be broken out of with a space, even when the value is escaped.

2. URLs: urlencode

When you build a link from a value, encode it so characters like &, # and spaces cannot change the meaning of the URL.

<a href="/search?q={{ term|urlencode }}">Search for {{ term|escape }}</a>

Note that the visible link text still uses escape. Encoding for the URL and escaping for HTML are two separate steps. Also never print an untrusted value as the whole href: a value like javascript:... is a URL scheme problem that neither filter solves. Build the path yourself and encode only the variable part.

3. JavaScript: escapejs and tojson

Inside a script block, HTML escaping is the wrong tool. Use escapejs when the value sits inside a quoted JavaScript string:

<script>
  var campaign = '{{ campaign|escapejs }}';
</script>

When you want to hand a value or a structure (such as a list from a HubDB query or a module field) to your script, tojson serializes it as JSON:

<script>
  var settings = {{ module.settings|tojson }};
</script>

A safer pattern that avoids inline scripts altogether is to put the value in a data- attribute with escape and read it from module.js:

<div class="promo" data-campaign="{{ campaign|escape }}"></div>
const promo = document.querySelector('.promo');
const campaign = promo.dataset.campaign;

Whichever route you choose, test the output in your own portal with a value containing quotes and angle brackets, and view the page source to confirm what was printed.

4. Plain-text excerpts: striptags and truncate

For cards and meta descriptions you often need a short plain-text version of HTML content:

<p>{{ content.post_body|striptags|truncate(140)|escape }}</p>

Order matters: remove tags first, cut the length second, and escape last so the final output is safe in HTML.

When not to escape

Rich text fields are meant to contain HTML. If you escape a rich text field, editors will see literal tags such as <strong> on the page. Print rich text from trusted editor fields as they are, and escape only values that visitors or external systems can influence: query strings, form inputs, and data pulled from outside HubSpot.

Likewise, do not escape twice. Applying escape to a value that was already escaped turns &amp; into &amp;amp; and shows garbled text.

A quick checklist

  • Identify the destination: HTML text, attribute, URL, or script.
  • Apply the matching filter at the point of output, not earlier in the template.
  • Quote every attribute value.
  • Prefer data- attributes over inline scripts for passing module values to JavaScript.
  • Test with a value like "><b>test</b>&x=1 and check the page source.

Sources

  • HubSpot Developer Docs: HubL filters reference (escape, escapejs, urlencode, tojson, striptags, truncate)
  • HubSpot Developer Docs: HubL variables, including the request variable
  • OWASP Cross Site Scripting Prevention Cheat Sheet (output encoding by context)