boomrrang

Boomrrang Security Overview

Effective date: 2 September 2026 Last updated: 2 September 2026 Owner: Founding engineering team Operated by: Leds Get It LLC, a limited liability company formed under the laws of Wyoming, United States Contact: security@boomrrang.com


1. Purpose and scope

This page describes how Boomrrang — a subscriptions application for Shopify — is designed, operated and secured. It is written for the security and procurement reviewers who have to approve installing an app that can charge your customers.

Scope: the Boomrrang application, its background workers, its webhook endpoints, its database and queue, and the operational practices around them. Out of scope: Shopify's own platform and security (see Shopify's trust documentation), the merchant's storefront and theme, and the merchant's own staff device security.

Two facts frame everything else:

  1. Boomrrang never handles payment card data. Cards are vaulted by Shopify and its payment providers. We move token references through Shopify's APIs; a card number never enters our process, our database, our logs or our backups. We are not a cardholder data environment.
  2. Boomrrang has no passwords. Every identity comes from Shopify OAuth. There is no credential store to breach and no password reset flow to abuse.

2. Architecture and tenancy isolation

2.0 Where it runs

Application compute — the TLS edge, the web application and the background worker — runs as isolated services on Fly.io (US deploy region iad — Ashburn, Virginia), with platform-managed TLS, per-app secrets, and no inbound access except HTTPS. The job queue is managed Redis at Upstash, provisioned through Fly.io in the same US region (iad), holding queue state and raw webhook payloads only transiently, until the worker processes them — the billing schedule of record lives in the database. The database is not on that infrastructure: it is managed PostgreSQL at Supabase (US region, us-east-1 — AWS N. Virginia), with encryption at rest and point-in-time-recovery backups (§11). This split is deliberate: everything durable and sensitive — the billing schedule, encrypted tokens, the ledger — lives with the managed database provider whose guarantees are contractual, while the compute host holds only the running processes and transient queue state, and can be rebuilt from scratch without data loss. All application hosting, processing and storage occur in the United States; personal data originating in the EEA, UK or Switzerland is transferred to the US for the processing described on this page. Each of these providers appears in our sub-processor list with regions and transfer mechanisms.

2.1 Origin separation

One deployment serves three logically distinct hosts, and each request is classified by host before anything else happens:

Host Role What lives there
auth.boomrrang.com Authentication Shopify launch, OAuth install, OAuth callback
{shop}.boomrrang.com Tenant One origin per merchant: the entire merchant-facing app
hooks.boomrrang.com Webhooks Shopify webhook ingestion only

Every route asserts the host role it is permitted to be served on and returns 404 otherwise. This is a tenant isolation control, not cosmetic routing: a tenant route reached on the auth host, or a webhook endpoint reached on a tenant host, does not execute.

Giving each merchant its own origin means the browser's own same-origin policy becomes part of the isolation model. Script, storage and cookies belonging to one merchant's origin cannot reach another's.

2.2 Session cookies are host-only, by construction

The session cookie uses the __Host- prefix, which browsers enforce: the cookie must be Secure, must be set from a path of /, and — critically — must carry no Domain attribute. A Domain=.boomrrang.com cookie would be sent to every tenant subdomain, which would destroy the isolation in §2.1. The __Host- prefix makes that mistake impossible to make by accident. The cookie is also HttpOnly (unreadable by script) and SameSite=Lax (not sent on cross-site requests).

2.3 Sessions are bound to one tenant

A session record stores the shop it belongs to and the user it belongs to. A session presented on a tenant origin that does not match the session's shop is rejected. A session cannot be moved between tenants.

2.4 The cross-origin handoff

A cookie cannot be set on the tenant origin from the auth origin — so login uses an explicit handoff instead of a cookie hack: the auth host issues a single-use, short-lived handoff code, redirects to the tenant origin, and the tenant origin consumes the code server-side and sets its own __Host- cookie. Only a hash of the code is stored, the code is marked consumed atomically, and the redirect target is a path validated against an allowlist — never an absolute URL, so it cannot be used as an open redirect.

2.5 Data isolation

Every tenant-scoped table carries a shop identifier, and every query is scoped to the session's shop. Deleting a shop cascades to its memberships, roles, sessions, contracts, events and receipts.


3. Authentication

  • No passwords, anywhere. Identity is established by Shopify OAuth. Shopify authenticates the staff member — including with whatever multi-factor policy the merchant has configured — and we receive the result.
  • HMAC verification on entry. The launch request from Shopify is verified with a constant-time HMAC comparison over the query parameters, and a request whose timestamp is more than 60 seconds old is rejected. That closes the replay window on a captured launch URL.
  • CSRF protection on the OAuth round trip. A single-use state nonce is generated, stored as a hash with an expiry, and must match on callback. Consumption is atomic.
  • Two token types, used deliberately.
    • An online token (roughly 24 hours, tied to the individual staff member) is used only for merchant-initiated actions.
    • An offline token (obtained once at install) is used by background workers and webhook processing. Recurring billing must use the offline token — using an online token there would mean charges silently stop when a merchant logs out of Shopify.
    • Both are encrypted at rest (§5) and never leave the server.
  • Session records store a SHA-256 hash of the session token, not the token; an expiry; a revocation timestamp; a hash of the IP address, not the address; and the user-agent string. A stolen database gives an attacker no usable session token.

4. Authorization

Shopify authenticates; Boomrrang authorizes. Shopify staff access to a store is not by itself access to Boomrrang — a person must additionally hold a membership in the shop.

  • Fine-grained grants. Permissions are modelled as individual grants (view subscriptions, edit subscriptions, cancel, edit selling plans, charge now, edit dunning policy, refund, export data, view customer personal data, manage users, manage roles, edit shop settings), bundled into roles. Every state-changing route checks its specific grant before acting.
  • Separate grants for the dangerous things. Actions that move money (billing:charge_now, billing:dunning_edit, billing:refund), actions that export data (data:export), and actions that reveal subscriber personal data (customer_pii:view) each require their own grant. None of them is implied by ordinary read access. Fine-grained checks were designed in from the first commit — retrofitting permission checks into an existing action surface is the refactor where one gets missed and someone who should not have it charges a customer.
  • Least privilege by default. Three system roles are seeded per shop: Admin (everything), Manager (day-to-day subscription operations — cannot manage users, edit dunning policy, or export data), and Viewer (read-only, and cannot see subscriber personal data at all). The installing merchant becomes Admin.
  • Last-admin protection. The application refuses to remove, suspend or downgrade the last remaining Admin membership on a shop, so a merchant cannot lock itself out of its own access controls.
  • Sensitive-grant visibility. Use of a money-moving, export, PII-viewing or user/role- management grant is recorded in the event ledger with elevated visibility (§7).
  • Membership binding. A person is matched first by their Shopify staff user id, falling back to email for a first-time invitation; on that first match the Shopify user id is bound permanently, so later access does not depend on a mutable email address.

5. Encryption and key management

Where Control
Shopify access tokens at rest AES-256-GCM, an authenticated cipher — a tampered ciphertext fails to decrypt rather than decrypting to something an attacker chose
Session tokens, handoff codes, OAuth state nonces Stored only as SHA-256 hashes; the plaintext exists only in the browser or the redirect, never at rest
IP addresses on sessions Stored only as a hash
Webhook payloads Stored durably only as a hash, for de-duplication and proof of receipt — the raw body exists only transiently in the queue until the worker processes it, and is never stored in the database
All network traffic TLS 1.2 or higher, HTTPS enforced
Database and backups at rest Encrypted by the managed database provider (Supabase)
Compute environment No durable personal data lives on compute: tokens are application-layer ciphertext in the managed database (itself encrypted at rest by Supabase), secrets are held in the compute platform's encrypted secret store (Fly.io app secrets), and queue state at Upstash is transient and encrypted at rest by the provider
Secret comparison Constant-time comparison for every HMAC and token check, to prevent timing oracles

Secrets management. All secrets — the Shopify API secret, the encryption key, the session secret, database and Redis credentials — are supplied to the application as environment variables through the compute platform's encrypted secret store (Fly.io app secrets), set only by an authenticated operator and not readable back in plaintext from the platform, with the authoritative copy held in a password manager rather than on any server. They are never committed to the repository; the repository contains only an example file with empty values. The encryption key never enters the database — the database holds token ciphertext, the compute environment holds the key, and neither alone yields a usable token. The application validates its secrets at boot and refuses to start if the encryption key is missing or the wrong length — a lazy failure discovered at the first request would mean tokens written in plaintext.

Key rotation. Rotating the encryption key requires re-encrypting stored tokens, which is a scripted operation. Rotation policy: annually, and immediately on suspected compromise or when someone with production access leaves.


6. Webhook and API integrity

  • Every Shopify webhook is verified by HMAC signature with a constant-time comparison before the payload is parsed. An unsigned or altered webhook is rejected.
  • The shop domain on every request is validated against the expected Shopify domain format before it is used.
  • Each webhook is recorded once by its Shopify webhook id, which makes ingestion idempotent — Shopify's at-least-once delivery cannot cause a duplicate side effect.
  • Webhook processing is asynchronous: the endpoint verifies, records and enqueues, then returns quickly. Work happens in a background worker with bounded retries and a dead-letter state, so a slow downstream never causes Shopify to consider the endpoint failed.
  • Security response headers are applied centrally to every response by a single module, so no route can be shipped without them.

7. Logging, monitoring and audit

7.1 Personal data is scrubbed before anything is emitted

All logging goes through a redaction layer. Tokens, request bodies and customer fields are never logged — this is a codified rule in the build contract, not an aspiration. Error reports sent to Sentry are scrubbed of personal data before transmission.

7.2 The event ledger

Every state-changing operation appends an immutable event in the same database transaction as the change itself. That is the single rule the whole audit design hangs on: a change cannot exist without its audit record, because both commit or neither does. Each event records the shop, who acted (user, system, Shopify, or customer), what kind of record changed, which record, the event type, and a request id that ties it to the originating request.

The ledger is required by design to contain no personal data — identifiers only, never names, emails or addresses. That is what makes it safe to retain for 24 months across an erasure request, and it is what lets us prove an erasure actually happened.

7.3 The PII access log

Every read of subscriber personal data writes an access-log row: which shop, which user, what was read, which fields, and the stated reason (merchant view, support request, dunning email). This is our commitment under Shopify's Protected Customer Data Level 2 requirements, and it is the record we use to answer, precisely, "who saw this customer's data, and when?"

7.4 Monitoring

Application errors go to Sentry (PII-scrubbed; Sentry's US data region). Structured application logs carry a request id that correlates a request across the web process and the background workers. Alerts route to our error tracker and to the founding engineering team, which is on call for them.


8. Data protection and minimisation

Minimisation is a design constraint here. The system deliberately does not hold:

  • payment card numbers, CVVs or bank details (Shopify vaults them);
  • subscriber names, shipping addresses, billing addresses or phone numbers — these are fetched from Shopify on demand, used to render a page, and discarded; every such read is logged (§7.3);
  • full customer profiles, order histories or browsing behaviour;
  • passwords of any kind;
  • raw IP addresses;
  • webhook payload bodies.

What is stored, and for how long, is set out in the Privacy Policy §3 and §9 and defined authoritatively in the internal retention policy at our internal retention policy. Summary: shop data purged immediately on shop/redact (which Shopify sends around 48 hours after uninstall) and within 30 days of uninstall in any event; subscriber personal data purged on customers/redact; personal-data-free event ledger 24 months; webhook receipts 30 days; PII access logs 12 months; encrypted backups 35 days.


9. Our own staff access to production

Control Position
Who has production access A named, minimal set of engineers; the current list is available to merchants under NDA
Basis for access Role-based and need-based; granted for a specific operational reason
Authentication to infrastructure Compute (Fly.io), database (Supabase) and DNS (Cloudflare) provider consoles: individual accounts with multi-factor authentication required; no shared logins anywhere. Shell access to production machines goes through the compute platform's authenticated tooling under those individual accounts — no password login, no shared accounts
Access to merchant personal data Only where required to resolve a specific support or incident case, and recorded in the PII access log with the reason
Joiners / movers / leavers Access reviewed on role change and revoked on the day someone leaves
Access review Quarterly, documented
Background checks Policy under definition — the production-access group is currently the founding team only
Confidentiality All personnel are bound by written confidentiality obligations
Security awareness training At onboarding and annually

10. Secure development and vulnerability management

10.1 In place

  • Module ownership. Every file has exactly one owner; security-sensitive primitives (cryptography, redaction, logging, headers, audit) live in a single owned module rather than being reimplemented per route.
  • TypeScript in strict mode, including strict index access checks, so a class of null and undefined defects fails the build rather than production.
  • Hand-rolled, reviewable cryptography built on Node's node:crypto for HMAC and webhook verification, rather than a large third-party SDK. This is a deliberate reduction of dependency surface and of unverifiable API behaviour, at the cost of writing (and carefully reviewing) the verification logic ourselves.
  • A minimal dependency tree. New dependencies are not added casually; each one is a supply chain we inherit.
  • Secrets never in source control.

10.2 Committed before general availability

The following are policy commitments that must be verifiably operating before this page is published:

Control Target
Automated dependency vulnerability scanning on every pull request and on a schedule [CI job — confirm implemented]
Automated dependency updates with review [Dependabot or equivalent — confirm]
Static analysis / linting enforced in CI, blocking merge [Confirm]
Secret scanning on commits and in history [Confirm]
Peer review required on every change to a security-sensitive module [Confirm branch protection]
Remediation SLAs: critical [7 days], high [30 days], medium [90 days] from confirmation [Confirm]
Independent penetration test before general availability, and [annually] thereafter [Not yet performed]
Formal compliance certification (SOC 2 / ISO 27001) Not held. We will not imply otherwise. If a certification is obtained, this page will say so and name the auditor and report date

We would rather publish an honest gap than an implied certification. If a merchant's procurement process requires evidence we do not have, we will say so directly.


11. Backup, restore and continuity

  • The primary database is backed up by the managed database provider (Supabase) with point-in-time recovery; backups are encrypted at rest and retained for 35 days (the window retention-policy.md commits to), then destroyed. [Confirm the Supabase project's PITR/backup configuration actually provides the 35-day window before publishing — the policy figure is ours, the mechanism is the provider's.]
  • The compute environment itself holds nothing that needs backing up: the application is redeployed from source control, secrets are restored from the password manager into the platform's secret store, and the queue holds only transient state. Loss of compute is a bounded outage — the billing schedule and all merchant data are in the managed database — and the rebuild procedure is documented and part of the restore drill below.
  • Backups inherit the isolation and access controls of the production database; access to restore is limited to the personnel in §9.
  • Restore is tested — a restore drill is performed quarterly and the result recorded. An untested backup is not a backup.
  • Deleted data is not resurrected. We do not restore erased records from a backup to circumvent an erasure request; where a restore is performed for an unrelated reason, erasures are re-applied to the restored data.
  • Billing continuity. The billing schedule lives durably in Postgres, not in the queue, and cycles are claimed with row-level locking and a unique idempotency key per cycle. An outage, a worker restart, or two workers racing therefore delays a charge rather than duplicating or losing one.
  • Recovery objectives are being validated with timed restore drills before we publish figures.

12. Incident response

We maintain a written incident response plan (internal, held with our compliance documentation alongside the retention policy in our internal compliance documentation). In summary:

  1. Detect — from monitoring and alerting, from a merchant report, or from a responsible disclosure.
  2. Triage and declare — an incident is assigned a severity and a single named incident lead within 1 hour of detection.
  3. Contain — revoke tokens or sessions, suspend the affected component or tenant, or take the affected path offline. Containment beats elegance.
  4. Investigate — the event ledger and PII access log are the primary forensic record, since every state change and every read of personal data is recorded with a request id.
  5. Notify — if personal data is affected, we notify each affected merchant without undue delay and in any event within 48 hours of becoming aware, with what we know, what is affected, and what we are doing. The merchant is the controller and notifies regulators (72 hours under GDPR Article 33, and the UK GDPR equivalent) and individuals; we give it the facts it needs to do so on time. As a US company we also comply, in parallel, with the US state breach-notification laws that apply to us. Where required, we also notify Shopify.
  6. Recover and verify — restore service, confirm the vector is closed.
  7. Post-incident review — a blameless written review with corrective actions and owners, shared with affected merchants on request.

13. Responsible disclosure

If you have found a security issue in Boomrrang, please tell us.

  • Email: security@boomrrang.com
  • Acknowledgement: within 2 business days.
  • Assessment and plan: within 10 business days.
  • Updates: until the issue is resolved, and credit in our advisory if you would like it.

Safe harbour. We will not pursue or support legal action against researchers who act in good faith under this policy: test only against your own installation or a store you are authorised to test, do not access, modify or exfiltrate another merchant's or subscriber's data, do not degrade service, do not run automated scanning that generates significant load, and give us a reasonable opportunity to remediate before disclosing publicly. If you inadvertently access data that is not yours, stop and tell us.

We do not currently operate a paid bug bounty.


14. What we do not do

A short list, because what a vendor refuses to do is often more informative than what it claims:

  • We never store payment card numbers, CVVs or bank details. Ever. Shopify vaults them.
  • We never write to your theme files or inject code into your storefront. We do not modify your theme, and uninstalling leaves no orphaned snippets behind.
  • We never sell, rent or share your data, or your subscribers' data, and we do not use it for advertising.
  • We never use subscriber data to train machine-learning models, ours or anyone else's.
  • We do not store subscriber names or addresses — we read them from Shopify when a page needs them, log the read, and discard them.
  • We do not use your data to build products for other merchants. Aggregate operational statistics contain no personal data and cannot be re-identified.
  • We do not log tokens, request bodies or customer fields.
  • We do not request Shopify scopes we do not need, and the scopes we do request are listed in the Privacy Policy §7.1.
  • We do not claim certifications we do not hold (§10.2).

15. Contact and documentation requests

Security contact security@boomrrang.com
Privacy contact privacy@boomrrang.com
Support support@boomrrang.com
Post Leds Get It LLC — postal address available on request from legal@boomrrang.com

Merchants may request, under NDA: our sub-processor list with contract status, our retention policy, our incident response plan, our completed security questionnaire, and — once performed — our penetration test summary.