# Security policy Review Manager is a Shopify app that stores product reviews written by shoppers, including names, phone numbers, and email addresses that those shoppers typed themselves. We take reports about it seriously and we would rather hear about a problem from you than from a merchant. **Owner:** Ali Bazlamit, sole developer and operator of the app. There is no security team behind this address, so please allow for one person's response times. **Last reviewed:** 4 August 2026. ## Reporting a vulnerability Email **ali.bazlamit@hotmail.com**. Include: - what you found and where, with a URL or route - the steps to reproduce it - what an attacker could reach with it - whether you accessed, altered, or retained any real data If you can, encrypt the report or send only a description first and hold the proof of concept until we reply. Please do **not** open a public GitHub issue for a security problem, and please do not post it anywhere public before we have had a chance to fix it. ### What we promise | Stage | Target | |-------|--------| | We acknowledge your report | within 3 business days | | We give you an initial assessment and a severity | within 7 business days | | We ship a fix for a critical or high issue | within 7 days of confirming it | | We ship a fix for a medium issue | within 30 days | | We ship a fix for a low issue | next scheduled release | We will keep you updated while we work, tell you when the fix ships, and credit you by name in `CHANGELOG.md` if you want the credit. We do not run a paid bug bounty and cannot offer money. ## Scope **In scope** - `https://reviews.alibazlamit.com` and every route it serves - this repository's application code, Dockerfile, `docker-compose.yml`, and `Caddyfile` - the review widget theme app extension in `extensions/` - anything that lets one merchant's data reach another merchant, or that lets an unauthenticated request read reviewer phone numbers or email addresses **Out of scope** - Shopify itself, `*.myshopify.com` storefronts, and the Shopify Admin. Report those through [Shopify's own programme](https://hackerone.com/shopify). - DigitalOcean, Let's Encrypt, and GitHub infrastructure - denial of service, volumetric, or brute force testing against the live host - reports generated purely by an automated scanner with no demonstrated impact - missing security headers or TLS configuration nits with no exploit path - social engineering of the operator or of any merchant **Rules** Test only against your own Shopify development store with the app installed. Do not access, modify, or delete data belonging to anyone else. Do not run load or stress tests. If you stumble into real personal data, stop, do not save it, and tell us in the report. ## Severity definitions | Severity | Meaning | Examples | |----------|---------|----------| | **Critical** | Remote takeover, or unauthenticated access to personal data across shops | Remote code execution on the droplet, SQL injection reaching the database, an unauthenticated route returning reviewer phone numbers, leaked Shopify access tokens | | **High** | Authenticated access to another merchant's data, or a break in a security control | One merchant reading another shop's reviews, forging an app proxy request, bypassing review request token validation, privilege escalation inside the admin UI | | **Medium** | Limited data exposure or a control that fails only in specific conditions | Reflected XSS in the review widget, an IDOR reaching non-personal records, a rate limit that can be bypassed to spam reviews | | **Low** | Weakness with no direct data impact | Missing hardening header, verbose error message, a dependency advisory with no reachable code path | ## Incident response procedure This is what happens when a security incident or a personal data breach is suspected. It applies whether we found it or you reported it. ### 1. Detect Signals we watch: a report to the address above, an unexpected pattern in the personal data access log (`type: "pii_access"`), Caddy access log anomalies, container restart loops, failed backup mails from cron, and Shopify or DigitalOcean abuse notices. The clock in step 4 starts the moment we become aware, not when we finish investigating. ### 2. Contain Immediate options, in order of preference: 1. Roll back to the previous known-good image by redeploying the last good SHA through the blue-green workflow. 2. Take the app offline at the edge by stopping the `caddy` container, if leaving it up means data keeps leaking. 3. Rotate the credential involved: `SHOPIFY_API_SECRET` in the Partner Dashboard, `POSTGRES_PASSWORD`, the CI deploy key, the GitHub deploy key, or the backup encryption key. 4. If Shopify access tokens may be compromised, uninstall or reinstall affected apps so Shopify issues fresh tokens, and tell the merchants why. Do not delete logs, containers, or backups during containment. They are the evidence for step 3. ### 3. Assess Write down, in a timestamped file kept outside the droplet: - what happened, and the earliest and latest time it could have happened - which shops are affected, by shop domain - which data categories are affected: reviewer name, phone, email, review text, order identifiers, merchant staff session data - roughly how many records, from the access log and database counts - whether the data was read, copied, altered, or destroyed - the root cause ### 4. Notify - **Merchants (our controllers): without undue delay and within 72 hours** of becoming aware, by email to the address on the store's Shopify account. Under the GDPR we are the processor, so this deadline is ours; the merchant then has their own 72 hour clock toward their supervisory authority. - **Shopify:** report through the Partner Dashboard for any incident touching protected customer data or Shopify access tokens, in line with the Shopify Partner Program Agreement. - **Shoppers:** where a breach is likely to result in a high risk to them, we support the merchant in notifying them. The merchant, as controller, sends that notice. - Partial notice beats late notice. If the assessment is incomplete at 72 hours, send what is known and follow up. ### 5. Remediate Ship the fix, redeploy, and confirm the vector is closed with a test. Rotate every credential that was exposed or might have been. Verify backups are still restorable with `scripts/pg-restore.sh --verify`. Only then bring anything back that was taken offline in step 2. ### 6. Post-mortem Within 14 days, write a short blameless post-mortem covering the timeline, the root cause, why it was not caught earlier, and the concrete change that prevents a repeat. Add a regression test for the vector. Record the outcome in `CHANGELOG.md` in general terms and keep the full write-up with the incident file. ## Security controls in place Documented so a reader can check the claims rather than trust them. - TLS on every request, certificates from Let's Encrypt via Caddy, HTTP redirected to HTTPS automatically. - Postgres publishes no port. It is reachable only on the internal `review_network` bridge. See `docker-compose.yml`. - SSH is key-only. `PasswordAuthentication no` and `PermitRootLogin prohibit-password` are set in `sshd_config`. See the hardening step in `DEPLOY_VPS.md`. - `ufw` allows only ports 22, 80, and 443. - Unattended security upgrades are enabled on the host. - Every database query is scoped to a single `shop` value, so one merchant's data cannot be returned to another. - Storefront requests are authenticated as Shopify app proxy requests; admin requests are authenticated as Shopify session tokens. - Review submissions are rate limited per submitter and per shop. - Reviewer phone numbers are masked to the last four digits before appearing in any log. Full numbers, email addresses, and review bodies are never logged. - Every admin page view that displays shopper data writes an access log line with the shop, the staff user ID, the route, and a record count. - HTTP access logs mask client IP addresses and redact secret query parameters. - Backups are gzipped then encrypted with `age` before they touch disk. The private key is not stored on the droplet. See `scripts/pg-backup.sh`. - Retention is enforced in code, not by policy alone. See `app/services/retention.server.ts`. We hold no security certifications. We are not ISO 27001 or SOC 2 certified and do not claim to be. ## Related documents - [Privacy policy](https://reviews.alibazlamit.com/privacy) - [Data processing addendum](https://reviews.alibazlamit.com/dpa) - [Deployment and hardening runbook](DEPLOY_VPS.md)