Snapshots

Locks are solid for five partners; four loose ends remain

Waiting on you
  • Google sign in with PKCE, signed 30 day sessions, and keys encrypted in a vault.
  • Only the promote script releases production, with a clean gate and rollback on failure.
  • Restore test passed on 25 Oct; backups run for 14 days plus a nightly export.
  • The default compute account still has project wide secret access across about 15 services.
  • Keys pasted in chat on 28 Sep are still waiting to be rotated.
4open security findings
Your call

Fix the default compute account this week, one service at a time?

Security, privacy and legal · 9.9

Security practices

DraftLast checked 2026-10-26Owner Param

Answer

How we keep brand data safe today, sign in, sessions, secrets, least access, the network edge and the audits already done, and what is still open before brands beyond the five partners arrive.

Today

Sign in and sessions

  • Google sign in with PKCE and a nonce; the id token's audience, issuer, expiry, nonce and verified email are checked. brew/auth.js:4-5, 221-239
  • Sessions are an HMAC signed cookie, HttpOnly, SameSite Lax, Secure on Cloud Run, for 30 days. brew/auth.js:54-64, 66, 245
  • Every token carries its type, so a connect state never works as a session. brew/auth.js:56-64
  • Each sign in has a session row; sign out ends it on every instance, and a root admin can end every session of one email. brew/sessions.js:1-4, 27-32
  • Redirects after sign in go only to our own paths. brew/auth.js:73
  • Local test sign in exists only off Cloud Run. brew/auth.js:250

Secrets

  • All keys come from Secret Manager; production uses its own *_PROD secrets for the session, vault and share links. brew/tools/prod-env.sh:10 brew/docs/production.md:14
  • Connected account keys are AES-256-GCM in the vault, never sent to a page and never logged. brew/vault.js:1-3
  • On production, share links are signed with HANDOFF_SECRET only, never the AI key. brew/handoff.js:18 handbook content/engineering/changelog.md:895
  • Without a session secret on Cloud Run, sign in turns itself off instead of using a default. brew/auth.js:46-47

Least access

  • Production runs as brew-prod-runtime@; staging's account cannot read production's secrets or data. brew/tools/prod-env.sh:4-6 memory brew-prod-backend
  • Web ingress is the load balancer only; the worker is internal; the database has a private IP and deletion protection. brew/docs/production.md:9-15 memory brew-prod-backend
  • Cloud Armor limits 3000 and 6000 requests a minute; load balancer logging is on; the CDN is off. memory brew-prod-backend
  • Every answer not marked public is private, so a cache never serves one viewer's data to another. handbook content/engineering/changelog.md:97
  • The only root admin on production is param@joinsquareup.com; every address at the two staff domains, joinsquareup.com and shopos.ai, gets full staff access. brew/tools/prod-env.sh:9

Outside input

  • Every fetch of a pasted address resolves DNS and refuses private, loopback and metadata ranges on each redirect. brew/reader/util.js:10-40
  • Headless Chromium runs with --no-sandbox in the reader and the PDF renderer. brew/reader/stages/site.js:103 brew/pdf/render.js:26
  • The demo site wraps fetch so it can never call a sending host or write to an account. brew/docs/handover/engineering/09-security-and-access.md:48

Release and recovery

  • Only tools/promote.sh releases production: backup, migrations, a clean gate that refuses test data, dummies and wrong settings, then traffic, with rollback on failure. brew/docs/production.md:25-33 memory prod-clean-only
  • Point in time recovery for 7 days, 14 daily backups, a nightly export to a separate bucket; a restore test passed on 25 Oct. brew/docs/production.md:35-45
  • Alerts email param@ and hello@: server errors, slow requests, worker lease lost, release failed, disk, connections, CPU, export failed, site down. brew/docs/production.md:112-115
  • Since 26 Oct GitHub Actions runs the whole test suite on every push and pull request, with every AI call mocked, so no key is needed in CI. brew/.github/workflows/test.yml:1-16
  • A data request deletion is a dry run first, refuses partners and protected brands, never revokes a platform grant and leaves one audit row. brew/db/brand-wipe.js:7-9, 24-32, 187-195

Audits done

Date Audit Outcome Source
15 Oct Handover audit E: accounts, demo, security; 11 findings S-1 to S-11 and 5 fix-now items N-1 to N-5 Shared links, team notes, mic, facts, PDF path, service account and share secret fixed the same day brew/docs/handover/engineering/audits/E-accounts-demo-security.md:57-115 handbook content/engineering/changelog.md:886-896
15 and 16 Oct Full audit Onboarding stream and Play titles made team only; notify takes only your own address; photo fetches through the guard; Slack actions and GA4 by property flagged memory brew-audit-2026-10-15
20 Oct QA audit, 4 auditors, about 86 findings P0s and most P1s live memory brew-qa-audit-2026-10-20
25 Oct Three independent reviews on storage, roles and security, about 45 findings, then QV rounds 2 and 3 All fixed with tests; sign out ends sessions; Arata guard no longer bypassable memory brew-prod-backend

Still open

  • The default compute service account keeps project wide secret access and run.admin, which affects about 15 other services. memory brew-prod-backend
  • STAFF_REQUIRE_HD is not set on production. brew/auth.js:240-242 brew/tools/prod-env.sh:9
  • Claiming by email domain is weak proof of ownership. brew/docs/handover/engineering/09-security-and-access.md:40
  • Chromium without its sandbox. brew/reader/stages/site.js:103

Tomorrow

Item Version Tag
Strip the default compute account to what Cloud Run needs v1 New, proposed
STAFF_REQUIRE_HD=1 and named staff on production v1 New, proposed
A security review before every new power, v2 to v4 v1 New, proposed
Store admin or DNS proof for claims v2 New
Write scopes held in their own table, used only after a person's yes v2 New
Chromium in its own sandboxed job v2 New, proposed
Ad rules with spend limits checked on the server v4 New

How we do it

  1. Never print, log or send a key to a page. New keys go to Secret Manager and tools/prod-env.sh.
  2. Every new route goes through sign in, genOk and the closed gate; test the outsider paths.
  3. Run the security and access tests before every deploy:
cd /Users/param/Documents/ChatGPT/brew && AI_MOCK=1 node --test test/security-fixes.test.js test/access.test.js test/qv1-roles-security.test.js test/qa-final-access.test.js
  1. Release only with tools/promote.sh; never edit it while it runs.
  2. Run the restore test monthly, as written in docs/production.md.
  3. After any leak of a key in chat or a file, rotate it the same day.

Numbers

Metric Definition Where measured Status
Open security findings Items in Still open This page 4 on 26 Oct
Days since restore test Days since the last passed restore test docs/production.md 1 on 26 Oct
Clean gate refusals Promotes the gate stopped brew-prod-clean job logs Proposed

Open

  1. Fix the default compute account now? It touches other company services. Proposal: yes, this week, one service at a time, each moved to its own account first.
  2. An outside penetration test? Proposal: one after v1 ships to the first 20 brands, not before.
  3. Rotate the keys pasted in chat on 28 Sep? The SquareUp tracking keys share this Google project. Proposal: rotate them now. memory squareup-tracking-structure
Sources
  • brew origin/main d6154b3: .github/workflows/test.yml:1-16, db/brand-wipe.js:7-32, 187-195, docs/production.md:112-115
  • brew/auth.js:4-6, 46-47, 54-64, 66, 73, 221-247, 250
  • brew/sessions.js:1-36
  • brew/vault.js:1-30
  • brew/handoff.js:18
  • brew/reader/util.js:10-40
  • brew/reader/stages/site.js:103
  • brew/pdf/render.js:26
  • brew/tools/prod-env.sh:1-12
  • brew/docs/production.md:9-15, 25-33, 35-45, 112-115
  • brew/docs/handover/engineering/09-security-and-access.md:1-60
  • brew/docs/handover/engineering/audits/E-accounts-demo-security.md:1-115
  • memory brew-prod-backend, brew-audit-2026-10-15, brew-qa-audit-2026-10-20, prod-clean-only, brew-access-rules
  • handbook content/engineering/changelog.md:81, 93, 97, 886-896

Source file content/security-privacy-and-legal/security-practices.md · For agents: Markdown · JSON