---
title: Theme extension cross-site scripting risk
description: >-
  Investigates untrusted values rendered without safe escaping in theme
  extensions.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/security/app-security-checks/theme-extension-xss
  md: >-
    https://shopify.dev/docs/apps/build/security/app-security-checks/theme-extension-xss.md
---

# Theme extension cross-site scripting risk

Investigates untrusted values rendered without safe escaping in theme extensions.

| Detail | Value |
| - | - |
| Check ID | `THEME_EXTENSION_XSS` |
| Severity | High |
| How it runs | Agent review |
| Applies to | Apps with a theme app extension |

***

## Vulnerable example

## extensions/reviews/blocks/review-list.liquid

```liquid
{% comment %}
  Customer-supplied review text, rendered raw into an attribute
  and an event handler. Either one executes on every storefront
  visit.
{% endcomment %}
{% for review in product.metafields.app.reviews.value %}
  <button onclick="showReview('{{ review.body }}')">
    {{ review.body }}
  </button>
{% endfor %}
```

***

## How to fix

Escape untrusted values and avoid raw HTML rendering.

## extensions/reviews/blocks/review-list.liquid

```liquid
{% comment %}
  Escape the text, and hand data to JavaScript through a data
  attribute rather than an inline handler.
{% endcomment %}
{% for review in product.metafields.app.reviews.value %}
  <button class="js-review" data-review="{{ review.body | escape }}">
    {{ review.body | escape }}
  </button>
{% endfor %}


<script src="{{ 'reviews.js' | asset_url }}" defer></script>
```

***

## Related

* [`shopify app security check`](https://shopify.dev/docs/api/shopify-cli/app/app-security-check), the command that runs this check
* [All app security checks](https://shopify.dev/docs/apps/build/security/app-security-checks)

***
