A product page can look perfectly normal while an app setting is doing something it should never do: supplying code that runs in a shopper’s browser. If you build Shopify apps, the important question is where editable data becomes executable content.
This guide was prompted by Kirill Platonov’s article on protecting theme app extensions. It takes a practical implementation angle: how to design app settings, render them safely, and test the result. It does not attempt to establish the cause or scale of the incidents discussed in that article.
What a theme app extension protects—and what still needs your attention
Theme app extensions let merchants add app blocks and embeds without manually changing theme templates. Shopify hosts extension assets and supports deploying updates across stores. Those are useful operational benefits, but the extension still needs safe rendering logic. Shopify’s extension overview explains the framework.
Think of a delivery widget with a heading, a background colour, and a link. Those three settings have different jobs. The heading is text, the colour is a constrained style choice, and the link is a destination that needs validation. Treating all three as arbitrary HTML makes the feature harder to secure and harder to maintain.
Start by deciding who should own each setting
A namespace that happens to contain your app’s name is not an access boundary. Shopify distinguishes merchant-owned metafields in ordinary namespaces from app-owned metafields in reserved namespaces. Merchant-owned fields can be changed by merchants and apps with the appropriate scopes.
Use app-owned fields for configuration your app should control, and check the definition’s access settings. Giving merchants write access changes who can edit the value. App-data metafields are a separate option tied to AppInstallation, useful for installation-specific configuration. They are not a place for API secrets. Shopify documents these distinctions in its metafield ownership and permissions guide.
For a migration, first inventory the fields your extension reads. Move the values you actually need, verify them, then update the reader. If an old shared field remains as a fallback, that old input is still part of the system. Set a date and a completion check for removing it.
Render text as text in Liquid and JavaScript
For ordinary labels, use Liquid’s escape filter in HTML text and quoted attributes. This small example uses a text setting from an app block:
<button class="delivery-toggle"
data-label="{{ block.settings.button_label | escape }}">
{{ block.settings.button_label | escape }}
</button>
Keep the click handler in the extension’s JavaScript asset. Read the data attribute there instead of building an inline onclick attribute around editable text. Shopify uses the same approach in its theme extension cross-site scripting guidance.
The output context matters. HTML escaping is not a universal answer for JavaScript, CSS, or URL safety. Shopify recommends the json filter when serializing data into JavaScript, and supported rich-content rendering where appropriate. See its Liquid output guidance. Avoid manually wrapping an unknown value in JavaScript quotes.
The browser can undo careful server rendering if you later insert the same value as raw HTML. For a plain status message, keep it simple:
const message = document.querySelector(".delivery-message");
if (message) {
message.textContent = settings.message;
}
Here, settings.message should already have passed your application’s type and length validation. textContent keeps the value in a text context. If the feature needs HTML, choose a maintained sanitizer and a narrow allowed format; do not assume removing script tags is sufficient. Shopify’s unsafe HTML assignment check covers common browser-side sinks.
Give merchants useful controls instead of a code box
A request such as “let me customise the banner” rarely needs an unrestricted JavaScript field. Ask what the merchant wants to change. A separate heading, approved colour picker, alignment choice, and validated link usually provide a much clearer editing experience.
If bold text or links are necessary, define that limited formatting explicitly. Shopify advises rendering settings as text or sanitizing intentional HTML with a strict server-side allowlist. Its guidance on unsafe text settings also covers previews, which deserve the same care as the live storefront.
For a delivery estimate widget, a useful configuration might be a lead-time number, an approved message template, and a display toggle. Keep the calculation in reviewed application code. This gives the merchant control over the feature without making every saved setting a new software release.
Check the route that saves the configuration
Safe Liquid output is one part of the review. The endpoint that writes a setting must also know which store is allowed to change it. Derive the shop from a verified authentication context, then authorize the requested change. A shop domain supplied in a request body cannot establish that permission. Shopify describes this risk in its configuration write security check.
If an app proxy is involved, verify its signature before trusting the forwarded parameters. That verification does not replace checks on whether a customer may access the requested data. Shopify’s app proxy authentication documentation explains the distinction.
My recommendation is to review configuration changes as a complete path: the editor, save endpoint, stored value, storefront renderer, and any browser code that consumes it. A safe component can still receive an unsafe value from a neglected part of that path.

Photorealistic editorial illustration showing a clothing product page on a laptop and smartphone beside a notebook. AI-generated conceptual image representing desktop and mobile storefront testing.
Check the same storefront flow on desktop and mobile. Image: AI-generated editorial illustration.
A practical test plan before release
Use a development store and harmless test data. The goal is to confirm that each setting has the intended meaning wherever it appears. I would include these checks in the release review:
- Enter a label containing an ampersand, quotes, and a harmless literal HTML fragment such as <b>Preview</b>. In a plain-text field, it should remain text without creating an element.
- Repeat the check in the app dashboard, support interface, and storefront. A safe product page does not prove the admin preview is safe.
- Test every supported language. Confirm that translated labels use the same rendering rules and that unexpected formatting is handled deliberately.
- Try saving invalid colours, oversized text, and unsupported URL schemes. Confirm the server rejects or safely normalizes them according to the field’s rules.
- Verify store isolation with two test installations: an authenticated request for one store must not change the other store’s settings.
- Check desktop and mobile product pages, cart interactions, and the expected checkout destination after each relevant app change.
- After moving metafields, test a store with missing new configuration. Confirm any migration fallback is temporary and does not silently restore unreviewed values.
These checks are a starting point, not proof that an app has no vulnerabilities. They make the intended behaviour concrete enough to review and repeat.
Use Shopify’s security check, then review the findings
Shopify documents the command shopify app security check for app security analysis. Follow the current CLI documentation for setup and available options. The checks include theme-extension output, unsafe HTML assignment, and configuration writes.
Review findings against the real data flow, fix the relevant issues, and run the checks again. An automated scan is most useful alongside a person who understands why a field exists and which stores or users can change it.
Where to begin on an existing app
Start with one visible feature, such as a product badge or delivery banner. List its editable fields and trace each one from saving to display. Replace unnecessary code settings with specific controls, fix unsafe output, and add a few focused regression checks before expanding the review.
For related Shopify work, you can view my Fez Delivery Co Shopify app integration project. If you need help reviewing a custom storefront feature or improving a Shopify integration, I’m available to discuss the scope.

