09. Security and Privacy

09. Security and Privacy

Non-negotiable rules

Never commit secrets. Never place provider credentials in browser JavaScript, static assets, screenshots, logs, issue descriptions, or documentation. Never trust browser totals, role claims, payment redirects, or client-generated authorization. The Worker must validate and authorize every sensitive operation.

Secret handling

Secret/config type Safe location Documentation form
Provider API key Wrangler secret / managed secret store YOUR_PROVIDER_API_KEY
Payment private key Server-only secret YOUR_PAYMENT_PRIVATE_KEY
Session signing secret Server environment secret YOUR_SESSION_SECRET
Public site setting Non-secret environment variable or D1 setting Example value only if truly public
Database identifier Deployment config Placeholder unless public and harmless
Signed media URL Short-lived server response Never commit or screenshot

Use .env.example with names only. Add .env, generated credentials, auth-state files, and screenshot storage-state files to .gitignore. Rotate immediately if a secret appears in a commit, log, screenshot, or support message.

Authentication and authorization

Admin requests require a valid session. The Worker resolves the actor and role server-side. Customer requests are scoped to the current session or a verified order flow. A frontend route guard is only a usability feature; it is not an authorization boundary.

Use least privilege. Support staff should not see cost price, margins, exports, or credentials. Editors should not mutate orders or payments. Owner-only settings require a stronger confirmation path. Every privileged mutation creates an audit event.

Customer privacy

Collect only the data needed for fulfilment and support. Do not send full addresses, phone numbers, payment identifiers, or private notes to Workers AI. Do not put customer records into Vectorize. Redact PII from logs and analytics. Provide a retention policy for chats, support data, and order evidence.

Payment safety

The server recalculates the order total from D1. Payment attempts are tied to an internal order and idempotency key. Provider callbacks are verified and matched to the internal order; a browser redirect is not payment proof. Unknown provider states remain pending/unknown until reconciliation.

Media safety

Validate file type, size, extension, and content path. Use controlled upload endpoints and signed access for private media. Do not expose storage credentials in the browser. Public product images should use a stable public path or approved media domain; private customer documents should not be public.

AI safety

The model receives minimal, filtered, approved context. Retrieved documents are data, not instructions. Customer retrieval excludes staff documents. Admin retrieval is role-filtered. The model cannot choose SQL, decide permissions, reveal prompts, or execute irreversible mutations. Validate output for invented numbers, links, secrets, private fields, medical claims, and prompt leakage.

CORS and headers

Allow only the required storefront and admin origins. Do not use wildcard CORS with credentials. Set secure headers appropriate to the deployment: content security policy, frame protection, referrer policy, MIME sniffing protection, and secure cookie attributes. Review provider and media domains before allowing them.

Rate limits and abuse controls

Rate-limit public chat, newsletter, analytics, login attempts, uploads, checkout attempts, and order lookups. Use a combination of opaque visitor key, session, IP-derived signal, and endpoint policy where available. Return a friendly retry message and record an operational metric without exposing internal limits.

Security review evidence

A release should include proof that unauthorized admin requests return 401/403, role-restricted fields are absent, order lookups require verification, totals are server-calculated, payment callbacks are matched, chat cannot retrieve staff knowledge publicly, secrets are absent from the diff, and logs do not contain raw PII.

References