If you discover a security vulnerability in ZAO OS, please report it responsibly:
- Do NOT open a public GitHub issue for security vulnerabilities
- Email security concerns to the project maintainer
- Include a description of the vulnerability, steps to reproduce, and potential impact
- Allow reasonable time for a fix before any public disclosure
ZAO OS never asks for, stores, or accesses any user's personal wallet private keys. This is a core principle.
- Farcaster Auth: Uses Sign In With Farcaster (SIWF) — signature-based authentication. The user signs a message in their wallet app; we verify the signature. We never see the private key.
- App Signer: The
APP_SIGNER_PRIVATE_KEYis an auto-generated wallet created at project setup (viascripts/generate-wallet.ts). It is used only to register Neynar managed signers for the app's Farcaster account. It is not any user's personal key. - XMTP Messaging: ZAO OS generates a dedicated, app-specific burner key for each user's XMTP messaging. This key is stored in the user's browser localStorage and is used only for XMTP message signing — never for on-chain transactions. The derived address holds no funds.
- Sessions use
iron-sessionwith encrypted, httpOnly, secure cookies - Cookie settings:
httpOnly: true,sameSite: 'lax',secure: true(production) - Session TTL: 7 days
- Admin access is restricted to hardcoded FIDs
- All API routes check authentication via session before processing
- Intentionally public routes (webhooks, registration, metadata) are documented
- All user input is validated with Zod schemas before use
- Neynar webhooks are verified via HMAC-SHA512 signatures
- Rate limiting is applied to prevent abuse
| Variable | Exposure | Purpose |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Public (browser) | Supabase project URL (safe to expose) |
NEXT_PUBLIC_SIWF_DOMAIN |
Public (browser) | Domain for SIWF verification |
NEXT_PUBLIC_NEYNAR_CLIENT_ID |
Public (browser) | Neynar OAuth client ID |
SUPABASE_SERVICE_ROLE_KEY |
Server only | Bypasses RLS — never in browser |
NEYNAR_API_KEY |
Server only | Neynar API access |
SESSION_SECRET |
Server only | iron-session encryption |
APP_SIGNER_PRIVATE_KEY |
Server only | App wallet for signer registration |
NEYNAR_WEBHOOK_SECRET |
Server only | Webhook HMAC verification |
- Supabase (PostgreSQL): Row Level Security (RLS) enabled on all tables. Service role key used only server-side in API routes.
- XMTP: Messages are end-to-end encrypted via MLS protocol. ZAO OS servers never see plaintext message content.
- Farcaster: Casts are stored on the Farcaster Snapchain network. ZAO OS caches them in Supabase for performance.
- localStorage: XMTP signing keys and DB encryption keys are stored in the browser. These are app-specific keys, not personal wallet keys.
- We don't store personal wallet private keys or seed phrases
- We don't ask users to paste or enter private keys
- We don't make on-chain transactions with user funds
- We don't store unencrypted passwords
- We don't use
dangerouslySetInnerHTML - We don't commit secrets to the repository
- We don't expose server-side API keys to the browser
Run npm audit to check for known vulnerabilities in dependencies. See research/40-codebase-audit-guide/ for the full audit methodology.
| Date | Scope | Findings | Report |
|---|---|---|---|
| 2026-03-14 | Full codebase | 1 critical (dep), 2 high, 4 medium, 4 low | research/40-codebase-audit-guide/AUDIT-RESULTS.md |