Skip to content
Policy

Security

Eturns is an AI agent that takes after-sales decisions on a merchant’s behalf. Security is the load-bearing dependency for that autonomy: if merchants cannot trust what the agent is doing, they will not let it act. This page summarizes the controls we have implemented.

Last updated · version 1.2

Platform edge

Public traffic hits Render web services with Render’s built-in edge: automatic DDoS protection (L3/L4 and platform L7), managed TLS certificates, HTTP→HTTPS, and an optional static edge cache. We do not operate a third-party CDN or WAF zone; DNS for *.eturns.app points directly at Render.

Authentication

  • Every Shopify webhook is HMAC-SHA256 verified before any side effect, using constant-time compare. Mismatch returns 401.
  • Customer portal actions verify a short-lived HttpOnly server-side portal session (minted after 6-digit email verification, buyer gift approval, or Shopify Customer Account OAuth 2.0 PKCE S256); post-purchase checkout extensions verify Shopify’s signed checkout token (HS256) and ignore client-supplied customer IDs.
  • Merchant admin routes verify the App Bridge session token; a JTI revoke list rejects logged-out tokens.
  • Installation uses Shopify Managed Installation (no legacy /auth redirect loop), exchanging validated session tokens via Shopify token exchange.

Authorization & data isolation

  • Row-Level Security is enforced on every shop-scoped Postgres table via FORCE ROW LEVEL SECURITY and a per-request shop_id GUC.
  • Every shop-scoped database transaction drops privileges via SET LOCAL ROLE to a restricted tenant role (NOSUPERUSER, NOBYPASSRLS); explicit system contexts are limited to install bootstrap, cross-shop webhook routing, and compliance/retention sweeps.
  • Shop access and refresh tokens are encrypted by the application before they are stored (AES-256-GCM with a fresh random nonce per token). The key is held in the hosting platform’s secret store, never in the database, and production refuses to store or read a token that is not encrypted this way.
  • Supabase Storage uses private buckets with short-TTL signed URLs that include a random token; nightly encrypted logical backups use RSA-4096 + AES-256-GCM with the private key held offline.

AI autonomy gates

  • Confidence + dollar thresholds gate every autonomous action. Each store’s dollar limit is set from its own order values (or by the merchant); no autonomous action above it without merchant approval.
  • The never-auto-block principle: no block-customer action is exposed to the AI tool catalog. Merchants decide; the AI surfaces signals.
  • Every model call goes through the Vercel AI Gateway; there are no direct calls to xAI, OpenAI, or Google.
  • Order contact fields never enter language-model prompts; structured case facts use sentinel IDs and customer messages pass through automated PII redaction.
  • Per-shop AI cost cap (circuit breaker) prevents runaway spend.

Decision trail & idempotency

  • Every AI decision writes a row to agent_decisions with model, prompt hash, context summary, tool calls, action, dollar amount, and reasoning trace. Kept 7 years.
  • Every webhook is keyed on X-Shopify-Webhook-Id plus (shop_id, topic, event_id, shopify_resource_id); succeeded deliveries are idempotent no-ops, unfinished rows re-dispatch safely, and out-of-order updates are rejected by (shopify_updated_at, shopify_triggered_at) watermarks.
  • Financial routes (approve, inspect, refund) require an Idempotency-Key header and an active staff seat.
  • Every state transition and merchant action is recorded in append-only audit_log_entries, backed by database-level DDL audit logging (pgaudit).

Rate limiting

Two inbound layers behind Render’s edge: an Express coarse IP rate limit on /api/admin, /webhooks, and /customer, and a shop-scoped Redis-backed limiter keyed on (shop_id, action_class, plan_tier). OTP, upload, financial, and admin-write action classes fail closed when Redis is unavailable; those surfaces never degrade to unlimited.

Supply chain

  • Secret scan with gitleaks on every push.
  • High+ CVEs block the build via pnpm audit:ci.
  • Weekly dependency audit job.
  • Trivy filesystem + IaC scan.
  • Dependabot version PRs.

Content Security Policy

A per-surface CSP is applied to every customer-facing route. Violations are reported to /api/csp-report, which is itself rate-limited per IP to prevent report flooding.

Reporting a vulnerability

If you believe you have discovered a security incident or vulnerability, contact contact@eturns.app. We will provide notices of security incidents as required by applicable law.

Questions about this policy? Write to us at contact@eturns.app, and a person on our team will reply.