Skip to content

Copiara is coming to the Shopify App Store. It is not listed yet.

Copiara

Security

Last updated: August 27, 2026

This is what Copiara is built and deployed to do today, written for the person who has to sign off on it. Where a control is not in place yet, it says so.

Where Copiara runs

The application runs on Google Cloud Run in the us-central1 region. The production database is Cloud SQL for PostgreSQL in the same region, reached over a managed connection path that requires either a Cloud SQL unix socket or TLS; a production configuration that provides neither refuses to start. Files live in Google Cloud Storage. Secrets are held in Google Secret Manager and read at boot, never committed to the repository or baked into an image.

This website and the Copiara admin app embedded in the Shopify admin are served from Vercel. Data is encrypted in transit and at rest using the encryption those platforms provide.

Your Shopify store itself runs on Shopify infrastructure, under Shopify’s own security program, which is outside this page’s scope and outside our control.

Single-region deployment is a current availability and residency boundary, not a global residency promise. A merchant that needs another region should raise it before installing so it can be scoped properly.

Separating one merchant from another

Copiara serves many merchants from one Cloud SQL deployment. Separation is enforced in the application, in layers, and every layer has to agree before a request touches a row:

  1. Shopify authenticates the person. An admin request carries a Shopify session token and a buyer request carries a Shopify customer account token, and Copiara verifies it and resolves the shop it belongs to.
  2. Role and permission checks decide whether that identity may take the requested action.
  3. Domain services scope every merchant-owned read and write to the resolved shop identifier. A route has to load a record through its shop fence before it can read or change it.
  4. Mutating operations write an audit entry through the single audit writer.
  5. Export and deletion paths use explicit shop predicates and are covered by tests that run against a real database.

A record identifier belonging to another merchant is not accepted as proof of access. Guessing one does not open it, because the fence filters before the identifier is ever honored.

Being direct about the limit: PostgreSQL row-level security is not enabled across these tables today. The application fence is the production control. The engineering trigger to revisit database-enforced row-level security is the third paying merchant, at which point the route and migration inventory gets reviewed and policies are added where they hold.

A dedicated environment, a merchant-specific region, isolated storage, restricted support access, and separate operational keys are scoped options rather than something the shared deployment quietly implies. They require a written architecture and operations review before a contract depends on them.

Identity and access control

Shopify is the identity provider. Copiara stores no passwords and runs no parallel identity system, and it never sees a Shopify credential.

  • Merchant staff reach the admin app inside the Shopify admin. Every request carries a Shopify session token, which is verified on arrival; an unverified or expired token is refused. Which staff can open the app at all is governed by the staff permissions the merchant sets in Shopify.
  • Buyers reach the storefront surfaces through Shopify customer accounts, using an OAuth flow against the merchant’s own store. Copiara resolves that session to the buyer’s company and location before it will answer with anything company-specific.
  • Copiara’s own roles sit on top of that identity, held in a single permission matrix that route gates read, so who may do what is one artifact rather than scattered checks.

Buyer sessions and staff sessions are separate lanes with separate credentials. A buyer credential cannot reach an admin surface, and margin, cost, and other internal fields are asserted out of buyer-facing responses rather than merely hidden in the interface.

Support access to a merchant’s installation is read-only and is recorded with its reason, actor, IP address, and user agent. Copiara has no mechanism to impersonate a buyer: Shopify customer accounts do not provide one, and we did not build a substitute.

Meeting Shopify’s app requirements

  • The app requests the narrowest set of access scopes that its features need. Shopify shows the merchant that list before install, and the app cannot act outside it.
  • Incoming webhooks are verified before they are processed, deduplicated by webhook id, and versioned by the record’s own timestamp, because Shopify does not guarantee delivery order and does not guarantee delivery at all. A reconciliation sweep repairs anything a missed webhook left stale.
  • The three mandatory privacy webhooks, customers/data_request, customers/redact, and shop/redact, are implemented. What each one does is written out in the privacy policy.
  • Shopify classifies B2B contact records as protected customer data. Handling them requires Shopify’s approval at the level the app’s scopes call for, which is part of the App Store review we have to pass before listing.

The audit trail

Every state change writes an audit entry: a quote approved, a price overridden, a draft order pushed, a permission changed. All of them go through one writer, which maintains a hash chain across the entries so tampering is detectable rather than invisible.

An entry records the actor, its visibility, the record touched, the action, a sanitized payload, and the request context. Security denials are recorded deliberately without passwords, raw tokens, or raw request payloads. Audit retention is merchant configurable and defaults to 730 days, pruned automatically.

An audit chain is an integrity control. It proves what happened; it does not stop an operator from making a change they were permitted to make. That is what the permission matrix, spend limits, and approval routing are for.

File storage

Private files and public assets are held in separate buckets, so an asset that has to be painted before anyone signs in can never sit alongside a merchant’s private documents. That split is structural, not a naming convention. Product images stay on Shopify’s CDN and are referenced by URL rather than copied.

Object paths carry a shop or record boundary. Upload URLs are signed, time-limited, and constrained by content type and size, and confirming an upload checks that the object sits inside the requesting merchant’s prefix and verifies it against the storage service before a reference is recorded.

Storage is not a second authorization system. A route authorizes the merchant before it returns a signed URL or accepts an object reference. Export download links expire after 24 hours.

Application hardening

  • Strict transport security, a content security policy, X-Content-Type-Options: nosniff, a strict referrer policy, and a permissions policy that turns off geolocation, microphone, and camera.
  • Framing is denied by default. The embedded admin app is the deliberate exception, framed only by the Shopify admin, as App Bridge requires.
  • Rate limiting on the API, with windows pruned on a schedule.
  • API keys are stored as hashes. Raw bearer tokens are never persisted anywhere, and Shopify access tokens are held per shop in encrypted storage.
  • Webhook deliveries record endpoint and response metadata, not credentials.
  • Cross-origin access is restricted to configured origins rather than left open.
  • Dependencies are tracked with automated update and security advisory pull requests across the repositories.

AI and customer data

The concierge and catalog knowledge paths use Vertex AI Gemini models and Vertex AI embeddings, called inside our own Google Cloud project. Prompts, tool context, catalog text, and generated responses are customer data when they contain customer content, and they are stored only through the retention paths described in the privacy policy.

Under the Google Cloud terms applicable to that project, customer data sent to Vertex AI is not used to train Google’s foundation models. We do not train models on one merchant’s data for another merchant or for general product improvement.

Prompt injection is treated as a real threat, not a hypothetical one. Merchant and buyer content reaching the model is data, never instruction authority. Tool access is registered and permission-checked against the signed-in user, so a message cannot reach another merchant’s store, change a role, or bypass an approval path. A model response is not a security boundary in Copiara, and nothing relies on it being one.

Backups and recovery

Cloud SQL automated backups and point-in-time recovery are the recovery boundary for the production database. Copiara does not run a second backup engine on top of them, and it is not a backup for your Shopify store: Shopify holds that data and remains its system of record.

Application retention and disaster recovery are separate things, and it matters for an erasure review: deleting a record in the app removes it from the live system, while a recovery snapshot can still hold it until the backup window rolls past.

We do not publish a recovery time or recovery point objective. A contract that needs one is a scope decision to make before signing, not something to read off this page.

Export, erasure, and uninstall

  • A merchant can ask us for a full export of the data Copiara holds for their store. Exports are retained 30 days; download links expire after 24 hours and can be reissued while the file exists.
  • Erasing a person replaces name, email, and phone with a tombstone and severs the link to their Shopify customer record. The record stays so audit and quote history still resolve.
  • Uninstalling the app from the Shopify admin ends our access immediately. Shopify sends shop/redact about 48 hours later, and we delete the Shopify connection data for that store: access tokens, the links to Shopify customers and products, queued work, and any parked data-request package.
  • A merchant’s Copiara workspace and the records the app created in it are retained and flagged on shop redaction rather than destroyed, so reinstalling returns to the same workspace. Deleting a workspace is a separate, deliberate step, and a merchant can ask for it.

A written inventory maps every table holding personal data to its retention, erasure, and export behavior, and it is maintained as a gate: a new field carrying personal data updates the inventory. We share it under NDA during a security review.

What we do not claim

We would rather tell you plainly what is missing than let a page imply otherwise.

  • The app is not listed on the Shopify App Store yet, and it has not completed Shopify’s app review or its protected customer data approval.
  • We do not hold a SOC 2 report. One is planned as we move from early merchants toward general availability.
  • We have not had an independent penetration test, and we will not say we have until we do.
  • We hold no formal certification and make no general regulatory compliance claim.
  • The database is single-region and shared across merchants. There is no multi-region deployment today.
  • Database-enforced row-level security is not enabled today. The application fence is the control.
  • There is no published uptime commitment, recovery objective, or bug bounty program.

What does exist as evidence: the audit hash chain, the permission matrix, the personal data inventory, shop-fence tests that run against a real database, and a written isolation posture document. Production configuration evidence such as IAM bindings, bucket policies, and backup settings is produced for a specific review rather than published here.

Reporting a vulnerability

Send it to hello@copiara.com with the subject line “Security”. Include what you found, the steps to reproduce it, and what access it gave you. We acknowledge within three business days and tell you what we are doing about it.

For good-faith research that stays within these bounds, we will not pursue legal action: test only against a store you control or your own development store, do not access, modify, or exfiltrate another merchant’s data, do not degrade the service or run denial-of-service or automated load testing, do not use social engineering or physical access, and give us reasonable time to fix the issue before disclosing it. Issues in Shopify itself go to Shopify, not to us. We do not run a paid bug bounty today.

Security review and questionnaires

Send them. If your procurement or security team has a questionnaire, wants the isolation posture document or the personal data inventory, needs a data processing agreement, or wants to walk through the architecture, write to hello@copiara.com. We answer honestly, including where the answer is not yet.

Current component state and any published incident notices are on the status page, which sits outside the merchant data plane: it carries no merchant references and its public responses expose no database identifiers or internal operational metrics.