> ## Documentation Index
> Fetch the complete documentation index at: https://topten.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Security

> The security model of Live Product Insights: proxy and webhook HMAC verification, post-authentication rate limiting, strict input allowlists, store-scoped data access, and the accepted risks we publish openly.

## Defense model at a glance

| Layer | Control |
| - | - |
| Storefront ingest (app proxy) | HMAC signature verified before anything is trusted; shop domain regex-validated pre-auth; requests for non-installed shops rejected `403` |
| Rate limiting | Keyed **only** on the signature-verified shop domain — 600 ingest batches/min, 1,200 stats polls/min |
| Request bodies | 64 KB hard cap → `413`; malformed JSON → `400`; wrong methods → `405` |
| Input validation | Allowlists on every field; malformed events dropped silently, never a `500` |
| Webhooks | HMAC verification on every handler via the Shopify library |
| Admin surface | Every admin route requires an authenticated session |
| Data access | Every query store-scoped; cross-shop isolation regression-tested |
| CSV exports | OWASP formula-injection escaping |
| Secrets | Environment variables only; never committed |

## Details that matter

**Rate limiting is post-authentication by design.** Early in development the limiter keyed on client-controlled headers, which let an unauthenticated flood poison a victim's bucket. It was rebuilt to key on the shop domain only after the proxy signature has been verified. The stats limit (1,200/min) is intentionally generous: the storefront widget polls every 5 seconds (12/min per open page), so the limit must absorb a store with a hundred concurrent product pages.

**Input validation is strict and fail-safe.** Session identifiers must be UUIDs; product identity must be a numeric id or a slug handle matching a tight pattern; event types and device classes are allowlists; quantities are clamped to 1–999; cart tokens must be hex strings of bounded length. Anything malformed is dropped without erroring — the ingest endpoint never rejects a batch because one event was bad.

**Store scoping is total.** Every analytics query filters by shop, and cross-shop isolation has dedicated regression tests (dedupe and identity resolution must never leak across shops). The order catch-up sync iterates all shops inside the scheduler, but every row it touches is processed under that row's own shop scope.

**No customer PII exists in the schema.** No names, emails, addresses, or full URLs — referrers are reduced to host names, identities are client-generated anonymous UUIDs, and the mandatory privacy webhooks reflect that (a customer data request is acknowledged with nothing to disclose; customer and shop redaction delete the rows that do exist).

**Secrets hygiene.** Secrets live only in environment variables or the Shopify CLI session. The test harness pulls signing secrets from the CLI at runtime and keeps them in process memory.

## Accepted risks, published

> [accordion] Proxy signature replay window (±90 seconds)
>
> Shopify's app-proxy signatures tolerate a timestamp window and include no nonce, so a captured signed URL can be replayed for up to about 90 seconds. Mitigations: per-shop rate limits bound the damage, and view dedupe means replays cannot inflate view counts. Accepted because full replay protection would require infrastructure Shopify's proxy contract doesn't provide.

> [accordion] Deferred dependency advisory (turbo-stream reflected-input DoS)
>
> A published advisory affects the stream-encoding package inside the framework. The fixed version is a breaking major upgrade, deferred deliberately; exposure is limited because no untrusted request input is reflected into loaders. Tracked for the next framework upgrade window.

> [accordion] Single-instance in-memory state
>
> Rate-limit buckets and dedupe locks assume one process. This is a scaling constraint more than an exposure: it is listed here because a multi-instance deployment silently weakens both controls until they are moved to a shared store — see [Deployment](https://topten.mintlify.site/development/deployment.md).

> [!NOTE]
>
> Security-relevant regressions are treated like any other defect: the failing case is reproduced as a test before the fix. The HTTP security suite (signature failures, rate-limit bursts, body caps, webhook HMAC) is the executable form of this page.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.