Shopify App Proxy Auth Bugs Hunters Keep Missing
App proxies let a Shopify app serve backend content under the shop domain at paths like /apps/your-app/.... Shopify signs those requests. Your job is to see whether the app verifies that signature—or trusts headers a browser can forge when hitting the app origin directly.
Two URLs, two trust levels
Hit the proxy URL on the shop: https://victim-shop.myshopify.com/apps/slug/resource. Then hit the app's real host if you can discover it from JS, partner dashboard docs, or residual DNS: https://app.vendor.com/proxy/resource.
If the direct host returns the same privileged JSON without a valid signature query (HMAC over the other parameters with the app's secret), the proxy "auth" was theater. That is a solid finding when the data is store-specific or customer-specific.
Verify the documented algorithm: sort parameters, drop signature, HMAC-SHA256 with the shared secret, hex digest compare. Bugs appear when:
- Comparison uses a loose equality or a truncated hash
- Signature is checked only for GET, not POST
- Extra parameters are ignored incorrectly, or duplicated keys confuse canonicalization
- Old shared secrets still validate after rotation
- Unicode or plus-encoding differences between Shopify's encoding and the app's verifier
Log the exact query string Shopify sent versus what your verifier rebuilt. Off-by-one parameter handling is surprisingly common in hand-rolled crypto helpers.
What to try on a dev store
Install the app on a store you own. Create two customer accounts if the proxy exposes customer records. Request another customer's wishlist, draft order, or loyalty balance by swapping ids after a valid proxied call—signature valid does not mean object authz is valid.
Also check admin-only proxy routes accidentally left under the storefront proxy path. An endpoint that returns all merchants' configs because it keys off an shop query string without tying to the authenticated shop in the signature is a cross-tenant issue. Session tokens for embedded apps are a different auth story—do not conflate them with proxy signatures in the writeup, but do test whether a proxy route accepts an Admin API token by mistake.
Theme app extensions and older script tags sometimes call the same backend with only a shop domain parameter. If those calls skip HMAC entirely, you have a simpler variant of the same class.
Liquid that prints proxy responses into the storefront can turn a data IDOR into XSS if the app returns unsanitized HTML. Keep that as a chained note with a harmless canary string, not a drive-by against real buyers.
Keep secrets secret
Never exfiltrate other merchants' data. Your store, your customers, canary SKUs. Report the exact URL pair, the missing or broken HMAC step, and the data class exposed. Include app version or extension version when visible so the vendor can diff.
Recommend verifying signatures with a constant-time compare, rejecting direct-origin calls that skip Shopify's signature, authorizing objects per shop and customer, rotating secrets after exposure, and monitoring for proxy requests that fail signature checks at volume. Shopify's proxy auth docs are short—read them once, then test where implementations drift.