Shopify App Security: The Checkout Hijack and What I Did
Shopify apps were hijacked to send shoppers to fake checkouts. What happened, what Shopify now asks, and why my app was safe.
In October 2026, hijacked Shopify apps sent shoppers to fake checkouts, and Shopify asked every app developer to act on security. Filter My Blog wasn't affected: its storefront code can't be made to run anything new, and it can't touch checkout. Here's what happened, what Shopify now asks, and how I secured this app before any of it.
I build and run Filter My Blog on my own. When a merchant installs it, they're trusting one person with a script on their storefront. I take that seriously, so here's the full picture.
What happened: Shopify apps hijacked to fake checkouts
On 10 October, developer Roman Zipp spotted a customer being sent from a real Shopify store to a fake checkout page. It looked right and asked for card details, but the domain wasn't the store's. His write-up of the Shopify checkout hijack traced it to a well-known app: Hulk Product Options.
The mechanism matters more than the name:
- The app's storefront script, served from Shopify's own CDN, was clean.
- On every page load, that script asked the app's own server for its settings.
- The settings response carried a field of custom JavaScript, about 22 KB of it, that the script then ran on the page.
- That code watched the checkout button and redirected shoppers to lookalike domains such as
checkout-confirm.top.
So nothing in Shopify's review or the app's published code was malicious. The attack lived in configuration that the app's server handed out, and the storefront ran it.
Over the following days two more apps confirmed incidents, as collected in Zipp's page of company statements:
- Selleasy (LogBase), 13 October: "an unauthorized party gained access to an internal Selleasy tool."
- Swym Wishlist Plus, 14 October: "an unauthorized change to the app's configuration."
None of them has published a full root cause. All three removed the injected code, and Shopify temporarily disabled the Hulk Product Options extension while it was cleaned up. Shoppers who typed a card number into one of the fake pages may have had it stolen. Those who paid with a wallet such as Shop Pay or PayPal are reported not to have been exposed.
Why it's happening now: AI finds weak spots faster
Shopify's own explanation is short: attacks are increasing "as AI improves at finding vulnerabilities."
The incidents point the same way. Qikify, an earlier victim, believes its incident came from a leaked credential. It warns that "credentials can leak from more places than before" and names AI coding agents with too many permissions as one possible source.
The same tools that help me ship faster help attackers search faster. Every app is now being read by machines that never get bored, so "nobody would find that" no longer counts as a defence.
What Shopify asked developers to do
On 20 October Shopify published Securing your app, together, marked action required and addressed to every app developer. It asked developers, that same week, to:
- Scan the app with the new security check in the AI Toolkit.
- Move to expiring access tokens, so a leaked token stops working on its own. Shopify says this will soon be required for all public apps.
- Use vulnerability scanners to confirm every endpoint is secured.
- Treat all rendered data as untrusted, whether it comes from metafields or your own servers.
- Check Dev Dashboard logs for suspicious API activity.
- Turn on two-step authentication for every account that touches the app: Partner account, hosting, CDN, code repository, email.
- Keep the emergency developer contact current.
- Review Shopify's security best practices.
Shopify is also tightening the rules for storefront app code, adding IP restrictions so an app's keys only work from its own servers, and raising App Store security requirements.
The scanner itself shipped a week earlier. Shopify's AI Toolkit security check runs locally with shopify app security check, or you ask your coding agent to "check my app for security vulnerabilities". The full list of app security checks has 37 checks, from unauthenticated routes and cross-shop data access to unescaped Liquid and unverified webhooks.
Point 4 is the lesson of the checkout hijack in one line. The hijacked apps trusted data from their own servers enough to run it.
How I built Filter My Blog so this doesn't happen
None of what follows was added in response. These are decisions from when I first wrote the app, and I re-checked each one against the code on 21 October 2026.
The storefront never runs code it's handed
This is the one that matters for the checkout hijack. The filter bar's scripts are static files that Shopify serves from its own CDN, the same files for every store. Your settings reach the storefront as data: colours, labels and tag order, stored in a shop metafield and rendered by Liquid. Every colour is checked against what a colour can look like before it's saved, and every value is escaped before it's printed.
The script does talk to my server, for blog search and click counts. It reads article addresses and numbers out of the answers, never markup and never code. The only markup it ever puts on the page is your theme's own article cards, taken from your own blog's pages. It never builds HTML from strings and has no eval. There's no setting, server response or admin field that can make it run something new. To do what was done to Hulk Product Options, an attacker would have to change the published app itself, which goes through Shopify.
One permission, and it's read-only
The app asks for exactly one Shopify permission: read_content, read access to your blogs and articles. It can't see customers, orders or payments, and it can't touch checkout. Even in the worst case, a stolen token for this app can read articles you've already published.
Expiring tokens were already on
Shopify's second ask was expiring offline access tokens. Filter My Blog has used them since the first line of code in August, two months before launch, so a token that leaks stops working on its own.
Every request is checked, and checked again
- Admin pages verify Shopify's session token on every load.
- Webhooks, including the mandatory privacy webhooks, are rejected unless Shopify's signature checks out.
- Storefront requests come through Shopify's app proxy, and the app verifies its signature. A valid signature only proves which store a request came from, so every blog and tag in it is also checked against that store's own settings before anything is read or written.
- Every database query is scoped to the store that made the verified request. No store can name another one.
- Paid features are enforced on the server. A disabled button in the admin is a courtesy, not the lock.
A database the internet can't reach
The database is Postgres on Supabase in the EU. Supabase's public Data API is switched off on purpose: row-level security is on for every table with no policies, and the public roles have no permissions. Only the app itself can read it.
Collect less, so there's less to lose
The analytics are daily counters per tag and per search term. There are no cookies, no IP addresses and no visitor IDs, and nothing that could tie a click to a person. Counters are deleted after about 400 days. When a store uninstalls, its sessions are removed straight away, and Shopify's shop/redact request 48 hours later deletes the store's data from the app's database. What we collect and the privacy policy list it all.
I ran Shopify's security check. Here's what it found
I ran the new check on 21 October 2026: Shopify CLI 4.9.4, ruleset 4.9.4, all 37 checks. One didn't apply, and my coding agent reviewed the 35 that need a human-style read. Most came back clean, including committed secrets, tenant isolation, app proxy signatures, theme extension XSS, scopes, webhooks and expiring tokens.
The automated pass also raised a few flags that turned out to be false alarms when I traced them. For example, it couldn't see that the admin pages authenticate through a shared helper. I checked each one by hand rather than waving them off.
It also found one real issue, on my marketing website rather than the app. The documentation search page put the search term into a script tag without escaping it. It never touched the app, any store or any merchant data, and I fixed it the same day. That's exactly what the tool is for.
While I was in there, I tightened a few more things the review turned up. There's now a daily cap on how many new search terms can be counted for a blog, so nobody can flood the analytics. The storefront endpoints are stricter about the names they accept, and output that was already checked on the way in is now escaped on the way out too.
Shopify says it plainly: a clean report "doesn't guarantee security." No app is unhackable, and I won't claim this one is. What I can promise is a small attack surface, nothing stored that isn't needed, and fast action when something turns up.
Why Filter My Blog wasn't affected
The checkout hijack needed two things: a storefront script that runs code it gets from the app's server, and a way to reach the checkout. Filter My Blog has neither. Its script only ever reads data, and the app has no access to checkout at all.
That's no accident. It comes from a few early choices: ask for as little access as possible, keep code and data apart, and assume every request is lying until proven otherwise.
What to do if you run a Shopify store
- Test your checkout today. In a private window, add a product to the cart and click Checkout. You should land on your real checkout, not a lookalike domain.
- Review your apps. Uninstall anything you no longer use. Every installed app is someone else's code on your storefront.
- Look at the permissions. An app that asks for far more access than its job needs deserves a question. Filter My Blog's full list is one word long; see what it does.
- Turn on two-step authentication for your Shopify account and every staff account.
- Check how apps reach your storefront. Theme app extensions, which Shopify reviews and hosts, are the safer pattern. Code an app fetches and runs at runtime is the riskier one.
If you think you've found a security issue in Filter My Blog, please report it through the contact form and choose "Security report". It comes straight to me, and the security page explains how I handle it. If you're a developer, run Shopify's check. It took me an afternoon, and it found something.
For more on how the app works under the hood, read why I built Filter My Blog or compare the plans.
Frequently asked questions
Was Shopify itself hacked?
There's no public evidence that Shopify's own platform was breached. The affected apps' statements describe an unauthorized change to app configuration or access to an internal tool. Shopify helped remove the scripts and has since asked every app developer to tighten security.
How do I check whether my Shopify checkout has been hijacked?
Open your store in a private window, add a product to the cart and click Checkout. Check that you land on your real Shopify checkout, on your own domain or checkout.shopify.com, not on a lookalike domain. If you see anything else, disable recently changed apps and contact Shopify Support straight away.
Could the checkout hijack happen through Filter My Blog?
Not the way it happened in October 2026. The hijacked apps ran JavaScript fetched from their own servers. Filter My Blog's storefront code never executes anything it fetches, and the app's only Shopify permission is read-only access to blog content. It can't touch checkout, customers or orders.
How can a Shopify developer check an app for security issues?
Run Shopify's app security check. With the AI Toolkit installed, ask your coding agent to check the app for security vulnerabilities, or run shopify app security check with the Shopify CLI. It covers 37 Shopify-specific checks, from unauthenticated routes to cross-shop data access.
What data does Filter My Blog store about shoppers?
None that identifies anyone. Analytics are daily counters per tag and per search term, with no cookies, IP addresses or visitor IDs. Counters are deleted after about 400 days, and a store's data is deleted from the app's database after it uninstalls.