| Version | Supported |
|---|---|
| 1.0.x | ✅ Current |
If you discover a security vulnerability, please report it privately before disclosing it publicly.
- Email: sfpcasaba@gmail.com
- Or contact the development team through private channels
- Type of vulnerability
- Steps to reproduce
- Potential impact
- Any screenshots or logs (if applicable)
- Verified Identity: Admin access requires a verified Firebase Auth email (Google OAuth or verified email/password)
- Allowlist System: Only identities in the
adminscollection (or theADMIN_EMAILSbootstrap env, reconciled intoadminsat session creation) can access admin areas and write privileged data. The env allowlist is matched case-insensitively; theadminsdocument ID is the exact token email (the security rules key on it verbatim) - Session Management: HTTP-only session cookies (5-day expiry),
securein production,sameSite=Lax, revocation-checked on every verification. Logout clears the cookie with matching attributes; it does not revoke the underlying Firebase session — the 5-day cookie expiry is the bound - CSRF posture: The session endpoint rejects mutating requests whose
Originheader doesn't match the request host, so cross-site POSTs can't plant a session and cross-site DELETEs can't force a logout. Next.js Server Actions enforce their own origin checks - Layered Protection: The edge proxy redirects
/adminrequests without a session cookie to/login; the authoritative check is server-siderequireAdmin()in the admin layout, which re-verifies the cookie and theadminscollection on every request - Privileged server actions: Every
use serverexport self-checksrequireAdmin()— the admin UI being unreachable by non-admins is never treated as the boundary - Roles:
admins/<email>docs carry arolefield (admin/editor, env-bootstrapped admins getadmin). No code path currently distinguishes roles — authorization is binary admin/non-admin - Functions:
triggerRebuild(manual HTTP rebuild) requiresAuthorization: Bearer <REBUILD_TRIGGER_TOKEN>and refuses all requests when the token is unconfigured.onFirestoreChangeis event-driven and needs no request authorization
- Firestore Security Rules: Server-side enforcement of data access
- Input Validation: All form inputs validated on both client and server
- TypeScript: Type safety prevents many classes of vulnerabilities
- No Direct Database Access: All database operations go through Firebase SDK
- Environment Variables: All secrets stored in environment variables
- HTTPS Only: Production enforces HTTPS
- CORS Configured: Proper cross-origin resource sharing settings
- No Raw HTML: Admin interfaces use structured fields, not raw HTML editing
- Dependency Updates: Regular security updates for all dependencies
- Never commit real credentials to any file. Only
.env.examplefiles (root andfunctions/) are committed, and they must contain placeholders only. .gitignoreignores all.env*files and*-firebase-adminsdk-*.jsonservice-account downloads. Do not weaken these patterns.- Secret values (never commit):
FIREBASE_ADMIN_PRIVATE_KEY,FIREBASE_ADMIN_CLIENT_EMAIL,VERCEL_TOKEN,ADMIN_EMAILScontents, session cookies, and any service-account JSON. - Public config, not secrets:
NEXT_PUBLIC_FIREBASE_*values andNEXT_PUBLIC_GA_IDare shipped to browsers by design — they identify the project but grant no access (Firestore/Storage rules enforce that). - Production secrets live in Vercel environment variables / Firebase config, never in the repository. CI runs credential-free with clearly fake placeholder values.
- If a real credential is ever committed: rotate it immediately, then coordinate history cleanup — do not force-push without team approval.
-
Dependabot (
.github/dependabot.yml) opens weekly grouped PRs for minor/patch updates in the root andfunctions/npm trees plus GitHub Actions. Major upgrades open individually for review. -
Audit both trees periodically:
npm audit # root, full tree npm audit --omit=dev # root, production only (cd functions && npm audit) # functions, full tree (cd functions && npm audit --omit=dev) # functions, production only
-
Apply
npm audit fixfor low-risk patches only — nevernpm audit fix --forcewithout analyzing each major upgrade. -
Known unresolved items are tracked in GitHub issues (see #110 for the moderate transitive advisories that remain upstream-blocked in the
firebase-toolsdev chain and@google-cloud/storage'sgaxios/uuid).
- All GitHub Actions are pinned to immutable commit SHAs.
- Workflow permissions are least privilege (
contents: read). - PR checks require no secrets; the build uses placeholder public env vars.
- Firebase security rules are tested against the emulator suite on every PR.
- Use strong, unique passwords (Google or email/password accounts)
- Enable 2FA where the provider supports it
- Log out when finished
- Don't share credentials
- Report suspicious activity immediately
- Review security rules before deployment
- Never commit
.env.localfiles - Use
npm auditregularly - Keep dependencies updated
- Review Firebase console for unusual activity
- Single Factor Auth: No in-app 2FA (Google OAuth or verified email/password; provider-level 2FA is up to the account)
- Session Duration: Sessions last 5 days (set in
src/app/api/auth/session/route.ts) - No Audit Logs: Admin actions are not currently logged
- Add audit logging for admin actions
- Implement shorter session durations
- Add IP-based restrictions
- Implement rate limiting
- Add security headers (CSP, HSTS)
This security policy is part of our commitment to maintaining a safe and secure platform for SFPCA operations.