Skip to main content

About app security

Merchants trust Shopify with their business, and when they install your app, they extend that trust to you. Shopify provides tools to help you earn that trust, such as app templates and libraries that handle authentication, and app security checks that find Shopify-specific issues in your code.

Agentic development has changed the pace of security for both attackers and developers. AI agents find weaknesses in minutes that used to take weeks of manual review, and that capability is as available to attackers as it is to you. An app that was secure enough a year ago needs a stronger posture today.

The same tooling makes hardening your app faster than it has ever been. Our app security check and these guides help you (and your agent) implement our best practices across your apps.


Anchor to Vulnerabilities that attackers target mostVulnerabilities that attackers target most

Attackers look for the same few weaknesses across many apps at once, mostly ones that let them change what renders on a storefront or read and change another store's orders, customers, and settings. This list pulls those weaknesses from every section in Best practices by area, in priority order.

#VulnerabilityHow to fix it
1Endpoints that trust a shop parameterTake the store from a verified ID token, HMAC, or app proxy signature. See Authenticate every request.
2Unescaped or shared values in theme app extensionsEscape each value for its context, and render only settings that your app owns. See Escape every value for its context and Store storefront settings where only your app can write them.
3Runtime configuration and internal tools that reach storefrontsNever run fetched configuration as code, and hold staff tools to the same standard as your app. See Treat runtime configuration as data and Hold internal tools to the same standard as your app.
4Cross-shop data access (IDOR)Look records up by the authenticated shop and the ID together. See Scope every query to the authenticated shop.
5Unverified webhooks and app proxy requestsVerify the HMAC or signature before you trust any value in the request. See Authenticate every request.
6Leaked or non-expiring credentialsKeep secrets out of bundles and logs, and use expiring offline access tokens. See Keep secrets out of shipped code and logs and Use expiring offline access tokens.
7Stolen tokens used from an attacker's serversAllowlist your servers' IP addresses, so a leaked token can make GraphQL and REST Admin API requests only from them. See Restrict API access to your IP addresses.
8Compromised accounts around your appTurn on multi-factor authentication everywhere, and remove access when people leave. See Protect the accounts that control your app.

If your app stores custom CSS, JavaScript, or HTML, then also audit what's already stored.


Anchor to Security and the Shopify App StoreSecurity and the Shopify App Store

Shopify reviews every app's security before publishing it in the Shopify App Store. The review checks the security requirements for App Store review, such as TLS, closed network ports, and secure token generation, and the iframe protection that embedded apps need.


Anchor to Best practices by areaBest practices by area

Each area covers one part of your app. Each practice has its own page that explains what to do, why it matters, and how to do it. Many pages also explain how to verify it.

Your app's server and the app that you embed in the Shopify admin. Shopify's app templates handle many of these practices for you. If you don't use an app template, then these practices are critical. If you do, then check your app against them anyway.

PracticeSummaryHandled by the app template
Authenticate every requestTake the store from a verified ID token, app proxy signature, or webhook HMAC, never from a request parameter.Yes, through the authenticate helpers.
Scope every query to the authenticated shopLook records up by the authenticated shop and the ID together.No.
Render untrusted content as textUse textContent, not innerHTML. Sanitize HTML on the server with an allowlist, and validate URL schemes.Partly. React escapes JSX text. dangerouslySetInnerHTML and server-rendered output are yours.
Prevent injection and request forgeryBind SQL values, allowlist outbound hosts, authenticate state changes with a session token, redirect only to allowlisted URLs, and treat model output as untrusted.Partly. Session-token authentication covers CSRF, and Prisma binds query values. SSRF, redirects, and model output are yours.
Handle uploads as untrusted inputValidate, rename, and re-encode uploads, store them outside your app, and reject SVG, XML, and HTML unless you truly need them.No.
Validate cross-frame messagesCompare event.origin with === against an exact value, check event.source, and never post sensitive data to *.Partly. addDocumentResponseHeaders sets the frame headers. postMessage handlers are yours.
Set up iframe protectionSend a frame-ancestors directive that lets only the authenticated shop's admin frame an embedded app, or 'none' for a standalone app. App Store review checks for it.Yes, through addDocumentResponseHeaders.

Anchor to Storefront and theme app extensionsStorefront and theme app extensions

Theme app extensions, app proxies, and anything else your app renders on a storefront. Every value your extension renders must be escaped for its context, come from a source only your app can change, and never run as code.

PracticeSummary
Use theme app extensions instead of script tags (required)Script tags are deprecated and load code that merchants can't see or turn off. Theme app extension assets are versioned and deployed with your app.
Escape every value for its contextescape for HTML, json inside <script>, url_encode in URLs. Validate custom CSS when it's saved, because no filter makes it safe.
Store storefront settings where only your app can write themOther apps, staff, and translations can write to public namespaces. Use $app or app-data metafields, and migrate existing values.
Don't serve user-written code to storefrontsOffer structured settings instead of custom JavaScript, HTML, or CSS that your app supplies to storefronts at runtime.
Treat runtime configuration as dataNever run fetched configuration as code. Ship behavior in versioned extension assets, and fetch only data.
Declare your app's network accessList the hosts your app links to and the servers it loads from or sends requests to. We use the list to protect your app and monitor storefronts for malicious requests.

Anchor to Credentials and dataCredentials and data

Your app's credentials, store access, and merchant and customer data. Shopify limits what a leaked credential can do, and these practices make sure your app takes advantage of those limits and holds as little as it needs to.

PracticeSummary
Use expiring offline access tokens (required)A non-expiring token stays valid until uninstall or secret rotation. An expiring one lasts one hour. Required for public apps from January 1, 2027.
Restrict API access to your IP addressesA stolen token can call the GraphQL and REST Admin API from anywhere unless you allowlist the addresses your servers use. Shopify rejects requests from outside them with a 403.
Request only the access scopes that you useUse optional scopes for features that only some stores use, and revoke scopes you no longer need.
Keep secrets out of shipped code and logsBundles, theme assets, source maps, and logs are readable by others. Automated scanners search them for credentials.
Collect only the customer data that you needData you don't hold can't leak. Never capture login fields, DOM snapshots, or payment data.

Anchor to Infrastructure and accountsInfrastructure and accounts

The infrastructure around your app's code, including your servers, internal tools, and dependencies.

PracticeSummary
Expose only a hardened web serverOne audited ingress on the internet. Databases, queues, admin panels, and staging stay private. TLS everywhere.
Hold internal tools to the same standard as your appInternal tools are discoverable. Stored XSS in a staff tool becomes a cross-store attack.
Protect the accounts that control your appMulti-factor authentication on Partner, hosting, DNS, source control, registry, and email accounts. Remove access when people leave.
Keep dependencies and runtimes currentFewer, pinned, reviewed dependencies. Patch runtimes and rebuild base images on a schedule. Pin CDN scripts with Subresource Integrity.

Anchor to Monitoring and incident responseMonitoring and incident response

These practices help you maintain a strong security posture through your processes and automation.

PracticeSummary
Check your app on every releaseThe checks find Shopify-specific issues in minutes. Scan every codebase that touches merchant data, not only the app directory.
Review your app's API logsA leaked token shows up as API traffic from somewhere other than your servers. Filter by client IP and user agent.
Respond to a security incidentContain, revoke, preserve evidence, notify Shopify, scope the impact, fix the root cause, meet your obligations, write it up.
Audit stored settings and custom codeScan stored CSS, JavaScript, and HTML for script elements, unknown domains, eval and atob, and code that touches checkout or login.

The app security checks scan your app's source code for Shopify-specific issues, such as a route that doesn't authenticate requests or a database query that isn't scoped to one shop. Run them before you submit your app and on every release.

The app security checks don't cover every best practice in these docs. They can't check configuration outside your code, such as your hosting and accounts, or your team's processes, such as reviewing your API logs and responding to incidents. They also scan only the directories that you point them at. To include a separate backend or an internal tool, see Check your app on every release.

With the AI Toolkit installed, ask your coding agent to run them:

Example prompt

/shopify Check my app for security vulnerabilities

Was this page helpful?