I’ve observed that Shopify incorporates automatic escaping in their Liquid templates to protect against cross-site scripting (XSS) vulnerabilities. However, I couldn’t find this feature in the standard liquid gem.
Here’s what I’m looking at:
Template example: <span class="{{ product_class }}">{{ product_class }}</span>
User input: alert('malicious code')" onload="
Output from Shopify:
<span class="alert('malicious code')" onload="">alert('malicious code')" onload="</span>
Output from Standard Liquid gem:
<span class="alert('malicious code')" onload="">alert('malicious code')" onload="</span>
Example Ruby code I tested:
template_string = '<span class="{{ product_class }}">{{ product_class }}</span>'
liquid_template = Liquid::Template.parse(template_string)
result = liquid_template.render!('product_class' => 'alert(\'malicious code\')" onload="')
How does Shopify achieve this? I’m aware of the escape filter and the need for backend escaping, but their method seems to provide default protection without the hassle of adding filters manually, making it much tidier to use {{ value }} instead of {{ value | escape }} each time.
Does anyone know how they implemented this automatic escaping?