When the principal is a token: Shopify Admin API data theft
A leaked Shopify Admin API token pages through every customer and order. The principal is the app, not a login, so a password reset does nothing. Here is what actually contains it.
A leaked Shopify Admin API token does not crack a password. It authenticates as an app, and apps read data. When that token belongs to an over-scoped custom app, it can quietly page through your entire customer and order history.
How the attack works
The token starts calling the Admin API from an IP that app has never used. It pages sequentially through the customers and orders endpoints, pulling PII, order history, and payment metadata like card last-four, gateway, and billing region far beyond the app’s normal pattern. Then it registers an orders/create webhook to an external endpoint, so every new order is streamed out automatically even after you notice. In ATT&CK terms this is T1078, Valid Accounts, paired with T1567, Exfiltration Over Web Service.
Why it works
The custom app held far more Admin API scope than its job required, and its long-lived token leaked. Because the principal is a token and an app, none of the human-centric reflexes apply. The owner’s password was never used, so resetting it changes nothing while the token keeps reading.
How to fix it
Revoke the app’s Admin API token to kill the session, then uninstall or re-scope the app. The non-obvious move the scenario teaches is to hunt down the webhook: the orders/create subscription outlives the token and keeps leaking new orders unless you delete it. After that, scope the actual read from the Admin API and event logs filtered to the token and window, since granted scopes show capability, not what was accessed. As a class fix, re-scope every custom app to least privilege, rotate and vault secrets out of config, and restrict tokens to expected IPs where supported.
Practice it
We built this as a GraphLattice Range scenario so teams can rehearse revoking a token, killing its webhook persistence, and scoping the read from the right log.