Security
Last updated: August 12, 2026
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.
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 Account API session tokens are verified before any customer action; the sub claim is the source of truth and the body customer_id is ignored in production.
- Merchant admin routes verify the App Bridge session token; a JTI revoke list rejects logged-out tokens.
- OAuth install uses an HMAC-signed state cookie with nonce binding (HttpOnly, Secure, SameSite=Lax, scoped to /auth).
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.
- The application connects via a non-privileged role (no SUPERUSER, no BYPASSRLS).
- Shop access tokens are encrypted at rest (AES-256-GCM via Supabase Vault).
- Supabase Storage uses private buckets with short-TTL signed URLs that include a random token.
AI autonomy gates
- Confidence + dollar thresholds gate every autonomous action. Default $200 — no autonomous action above that 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 — no direct calls to xAI, OpenAI, or Google.
- No raw PII is sent to the models — case facts use sentinel IDs and structured fields.
- Per-shop AI cost cap (circuit breaker) prevents runaway spend.
Audit & idempotency
- Every AI decision writes a row to agent_decisions with model, prompt hash, context summary, tool calls, action, dollar amount, and reasoning trace. 7-year retention.
- Every webhook is deduplicated on (topic, shop_id, payload_id); duplicate Shopify retries are no-ops.
- Financial routes (approve, inspect, refund) require an Idempotency-Key header.
- Every state transition and merchant action is recorded in audit_log_entries.
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 security@eturns.app. We will provide notices of security incidents as required by applicable law.
Questions about this policy? Email support@eturns.app.