Security
Last updated
Reporting a vulnerability
If you believe you have found a security issue in HookRescue, please email security@hookrescue.com. We treat security reports as a top-priority signal and triage them ahead of feature work.
Response commitments:
- Initial acknowledgement within 2 business days of receipt.
- For reports indicating active exploitation, credential disclosure, or remote code execution, we aim to acknowledge and begin triage within 24 hours, including weekends.
- Status updates at least every 7 days while a report is open.
Coordinated disclosure: we operate on a 90-day coordinated disclosure window from the date of initial report. We will request extensions only when a fix requires coordinated work with a subprocessor or a non-trivial migration; in those cases we will keep you informed of timelines and never silently extend.
In-scope:
- The production application at
hookrescue.comand any subdomains we own. - Our public API and webhook ingestion endpoints.
- The authentication, session, and account-management surface.
- Mobile-rendered views of the application, where applicable.
Out-of-scope:
- Third-party services we depend on (Heroku, Cloudflare, our transactional email provider, LemonSqueezy). Please report issues in those services directly to the respective vendor; we are happy to coordinate if a finding has implications for our customers.
- Findings that require physical access, social engineering of our staff, or denial-of-service via volumetric traffic.
- Reports generated solely from automated scanners with no demonstrated impact.
Safe harbor: we will not pursue legal action against researchers acting in good faith — meaning you avoid privacy violations, data destruction, service disruption, and you give us a reasonable window to remediate before public disclosure. If a third party brings action against you for activity that complied with this policy, we will make it known publicly that your activity was authorized.
A machine-readable contact record is published at https://hookrescue.com/.well-known/security.txt.
Encryption
At rest. Every per-source signing secret, every customer Shopify Admin API access token, and every other sensitive field on the account, store, and webhook-source models is encrypted with AES-GCM via Rails 7.1's built-in ActiveRecord encryption. Encryption keys are managed outside the application database and are rotated independently of the encrypted records. Plaintext secrets exist only transiently in process memory while a request is being handled — they are never logged, never written to disk in cleartext, and never serialized into background-job arguments.
In transit. All customer-facing endpoints require TLS 1.2 or higher, with TLS 1.3 preferred where the client supports it. HTTPS is enforced in production, with redirect-on-HTTP and HSTS headers on every response (HSTS preload submission is pending). Internal service-to-service traffic — application dynos to Postgres, application dynos to Redis, worker dynos to the primary database — runs over Heroku's private network with TLS termination at the addon boundary.
HMAC. Every inbound Shopify webhook is verified with HMAC SHA-256 against the per-source signing secret. The comparison is constant-time and wrapped in a length guard so an attacker cannot probe digest length via timing. We support a 1-hour grace window during secret rotation (extended to 72 hours for the GDPR-mandatory topics: customers/data_request, customers/redact, shop/redact) so that rotations are never the cause of a dropped compliance webhook.
Authentication and access control
User authentication is built on Devise with eight modules enabled:
database_authenticatable— bcrypt-hashed passwords, never stored or logged in cleartext.registerable,recoverable,rememberable,validatable— standard account lifecycle.confirmable— email confirmation required before privileged actions.lockable— automatic account lockout after a threshold of failed attempts.timeoutable— idle sessions expire and require re-authentication.trackable— last sign-in IP, timestamp, and count are recorded for every account.
Multi-factor authentication (TOTP, with WebAuthn under evaluation) is on the near-term roadmap and will be available to all paid plans on launch.
Sessions are stored in encrypted, signed cookies scoped to the root domain, with secure: true in production and same_site: :lax to defeat the common CSRF vectors that survive same-site defaults. CSRF protection is enforced application-wide via Rails authenticity tokens (protect_from_forgery with: :exception); any non-GET request without a valid token raises an exception rather than silently failing open.
Privileged operations — staff impersonation, manual replay of another tenant's events, secret rotation on a customer's behalf, dead-letter-queue resolution — are gated behind an internal admin allowlist. Every privileged action writes an entry to the audit log capturing the actor's user_id, the target resource, the timestamp, and the outcome. Audit log entries are append-only from the application's perspective and are retained alongside the primary database backups.
Webhook integrity
Webhook integrity is the core of what HookRescue does, so it gets its own section.
Inbound verification. Every webhook arriving at our ingest endpoint is verified with HMAC SHA-256 against the per-source signing secret before any further processing. Verification happens before the payload is parsed, before any database write, and before the work is enqueued. A failed verification returns 401 immediately and is recorded for review without persisting the body.
Rotation grace. When a customer rotates a signing secret, we accept signatures from both the old and new secret for a 1-hour grace window, extended to 72 hours for the GDPR-mandatory topics whose loss would create a compliance gap. Once the window closes, the old secret is no longer accepted.
Deduplication. Every event is keyed by X-Shopify-Webhook-Id, with a Postgres unique constraint on the dedup key. The same webhook ID can never persist twice, regardless of how many times Shopify retries delivery into us. Forward enqueueing is further guarded by sidekiq-unique-jobs keyed on the event ID, so concurrent ingestion paths cannot enqueue duplicate forwards.
Atomic claims. Workers claim events for delivery via an atomic Postgres UPDATE ... WHERE locked_until IS NULL OR locked_until < NOW() so that two workers can never deliver the same event, even under aggressive scaling or network partitions.
Outbound re-signing. This is the property that lets HookRescue sit transparently in front of an existing Shopify integration: we re-sign every forwarded payload with the customer's secret using the same SHA-256 HMAC mechanism Shopify itself uses. The customer's existing handler verifies our signature with the exact same code path it already uses for direct Shopify deliveries — no SDK swap, no special-cased verification, no trust in our IP space. If we disappear tomorrow, the handler keeps working when pointed back at Shopify.
Body-size caps are tiered per topic class: 2 MB default, 5 MB for GDPR topics, 10 MB for large-payload topics such as metaobjects/* and bulk_operations/*. Oversize bodies are rejected at the edge with a structured error rather than silently truncated.
Per-merchant rate limiting uses a Redis-backed token bucket so that one noisy store cannot starve another tenant of ingest or forward capacity. Worker queues themselves are strict-priority: critical (GDPR + lifecycle) > ingest_post > forward > retry > reconcile > replay > maintenance > default. Compliance and lifecycle work always preempts everything else.
Infrastructure
HookRescue is hosted on Heroku in the US region. Postgres and Redis are provisioned via Heroku Addons and run inside the same private network as the application dynos. Cloudflare sits in front of the application as CDN, WAF, and DDoS edge.
All public traffic terminates TLS at Cloudflare and is re-encrypted to Heroku — there is no plaintext hop on the public internet. Customer data does not egress outside the US region without an explicit cross-region transfer agreement; we do not replicate to other regions for performance or convenience.
Production and staging are fully isolated environments with separate credentials, separate databases, and separate Cloudflare configurations. Production access for engineers is gated by SSH key, account 2FA, and the same admin allowlist that gates privileged in-app actions.
Data isolation
HookRescue is multi-tenant at the row level. A Multitenant concern enforces that every model carrying tenant data exposes an account_id column and that every query is scoped by it. Composite indexes on (account_id, ...) ensure that tenant scoping is not just a correctness property but also the primary access path — a query that forgot to scope would not be merely insecure, it would be visibly slow in development.
There is no shared-tenancy mode. There are no "global" rows that bridge accounts. Background jobs carry account_id in their arguments and re-scope on dequeue.
Backups
Heroku Postgres provides continuous protection: continuous WAL archive plus a daily logical snapshot. We retain point-in-time recovery for the last 7 days, which is sufficient to recover from accidental destructive operations (a bad migration, a mis-targeted delete) without losing more than a few seconds of writes. Backup storage uses the same encryption posture as the live database — encrypted-at-rest by the addon — and recovery procedures are exercised on a recurring schedule, not just on incident.
Incident response
We maintain an internal runbook for security incidents covering detection, containment, eradication, recovery, and post-incident review. On confirmation of a material breach affecting customer data, we will notify affected customers within 72 hours, in line with GDPR Article 33 timelines, even where GDPR does not formally apply. Notification includes the nature of the incident, the data categories involved, the steps we have taken, and the steps customers should take.
A written post-incident report is shared with affected customers within a reasonable window after recovery, covering root cause, timeline, and remediation. We do not bury incidents in vague "operational issues" language.
Vendor security
The subprocessors handling customer data on our behalf are:
- Heroku — application hosting, Postgres, Redis.
- Cloudflare — CDN, WAF, DNS, DDoS protection.
- LemonSqueezy — billing and merchant-of-record processing.
- Transactional email provider — outbound transactional mail (account confirmation, password reset, alerting).
Every subprocessor is evaluated for security posture, certification status, and data-handling guarantees before onboarding, and is reviewed at least annually thereafter. The current public subprocessor list is maintained at https://hookrescue.com/privacy and is updated before any new subprocessor begins handling customer data.
Compliance roadmap
We want to be straightforward about what is in place today and what is in flight:
- SOC 2 Type II — on the post-beta roadmap. Not yet certified. We are aligning controls against the Trust Services Criteria now so that the first audit window can begin cleanly.
- GDPR — we operate within GDPR's substantive requirements (encryption, breach notification timelines, data subject request handling via the standard Shopify GDPR webhooks). A standardized DPA is available on request and a self-serve version will be published once finalized.
- Bug bounty — a structured bug bounty program is planned for post-beta launch. In the meantime, vulnerability disclosure is via email per the policy above, and we honor the same safe-harbor terms a formal program would offer.
We will not claim certifications we do not hold.
Open source and transparency
The HMAC verification logic HookRescue uses on the inbound and outbound paths is open source and available for review, so customers and researchers can audit exactly how signatures are computed, compared, and rotated rather than taking our word for it.
We publish a public changelog for security-relevant releases — secret-handling changes, authentication changes, dependency upgrades that close known CVEs. Security advisories with CVE references where applicable are published at https://hookrescue.com/security/advisories (forward-looking; the index is maintained alongside the public changelog).
Contact
Security disclosures: security@hookrescue.com
A PGP key is available on request for sensitive reports — please send a brief, unencrypted email asking for the key and we will reply with the current public key fingerprint and key material before you transmit anything sensitive.
A machine-readable version of this contact information, conformant with RFC 9116, is published at:
https://hookrescue.com/.well-known/security.txt
For non-security inquiries, please use the standard support channels rather than the disclosure address — it keeps the security queue clear for what it is meant for.
See also
- Privacy Policy — what data we collect, retention windows, subprocessors.
- Terms of Service — what you agree to when using the service.