This document outlines security practices, credential management, and incident response procedures for the QALA project.
CRITICAL: Never use production credentials in development!
| Environment | Supabase Project | Purpose | Who Has Access |
|---|---|---|---|
| Development | qala-dev (separate project) |
Local testing, feature development | All developers |
| Production | qala-production |
Live users, real data | Admin only (@osiah) |
✅ ALLOWED:
.env.local(gitignored, never committed)server/.env(gitignored, never committed)- GitHub Secrets (for CI/CD)
- Vercel/Railway environment variables (encrypted)
- Password managers (1Password, Bitwarden, etc.)
❌ FORBIDDEN:
- Committing
.envfiles to git - Sharing credentials via email/Slack/Discord
- Hardcoding secrets in source code
- Storing secrets in documentation files
- Uploading
.envfiles to cloud storage
| Credential Type | Rotation Frequency | How to Rotate |
|---|---|---|
| Supabase API Keys | Every 90 days | Dashboard → Settings → API → Reset |
| JWT Secrets | Every 180 days | Generate new: openssl rand -base64 32 |
| Stripe API Keys | On developer offboarding | Dashboard → Developers → Roll keys |
| Database Passwords | Every 90 days | Supabase → Settings → Database → Reset password |
| Google Translate API | Every 90 days | Google Cloud Console → Regenerate |
| Webhook Secrets | On breach only | Service provider dashboard |
Set calendar reminders for credential rotation!
| Level | Permissions | Who Gets This |
|---|---|---|
| Admin | Full access, settings, secrets, force push | @osiah (project owner) |
| Maintainer | Write access, merge PRs, cannot change settings | Core team members (trusted) |
| Contributor | Read-only, submit PRs via fork | External developers, new team members |
| None | No access | Public, former team members |
New Developer Onboarding:
-
Initial Setup (Day 1):
- Add as Contributor (read-only)
- Provide development
.env.exampletemplate - Share development Supabase credentials ONLY
- No production access
-
After 2 Approved PRs:
- Upgrade to Maintainer (if core team)
- Still no production credentials
-
Never Share:
- Production
.env.local - Production Supabase service_role key
- Stripe live API keys
- Admin dashboard access
- Production
Developer Offboarding Checklist:
- Remove from GitHub repository (Settings → Collaborators)
- Revoke Supabase Dashboard access (if granted)
- Rotate shared development credentials
- Rotate production credentials if developer had access
- Review audit logs for last 30 days
- Check for any backdoors or suspicious commits
- Remove from team communication channels
- Deactivate any service accounts created for developer
These MUST be enabled on GitHub:
Go to: Settings → Branches → Add rule for main branch
Required Settings:
✅ Require pull request before merging
✅ Require approvals: 1
✅ Dismiss stale pull request approvals when new commits are pushed
✅ Require review from Code Owners
✅ Require status checks to pass before merging
✅ Require branches to be up to date before merging
Status checks:
- lint
- type-check
- test
- build
✅ Require conversation resolution before merging
✅ Require signed commits (recommended)
✅ Include administrators (IMPORTANT: Even owner must follow rules)
✅ Restrict who can push to matching branches
Add: @osiah (admin only)
❌ Allow force pushes: Nobody
❌ Allow deletions: Disabled
Why this matters: Without branch protection, CODEOWNERS is useless. Anyone can push directly to main and bypass security.
Automatically enforced via Husky on every commit:
Security Checks:
detect-secrets- Scans for API keys, passwords, tokensenv-file-check- Blocks commits containing.envfilessecret-scan- Pattern matching for hardcoded secrets
Code Quality:
- ESLint - Code linting
- Prettier - Code formatting
- TypeScript - Type checking
Bypassing Hooks:
# ⚠️ DANGEROUS - Only use for emergencies
git commit --no-verify
# Better approach: Fix the issue
npm run lint:fix
npm run formatIf you need to bypass: Ask yourself why. Usually there's a better solution.
IMMEDIATE ACTIONS (within 1 hour):
-
Assess Scope:
# Check what was exposed git log --all --full-history -- '*.env*' git log -p --all --full-history -- '*.env*' | grep -i "key\|secret\|password"
-
Rotate ALL Exposed Credentials:
- Supabase: Dashboard → Settings → API → Reset service_role key
- Stripe: Dashboard → Developers → Roll keys
- Google: Cloud Console → Regenerate API key
- JWT: Generate new:
openssl rand -base64 32
-
Update Production:
- Vercel: Settings → Environment Variables
- Railway: Variables tab
- Restart all services after updating
-
Remove from Git History (if committed):
# ⚠️ DANGEROUS - Creates new history, requires force push git filter-branch --force --index-filter \ "git rm --cached --ignore-unmatch path/to/.env" \ --prune-empty --tag-name-filter cat -- --all # Force push to remote (requires admin) git push origin --force --all
-
Revoke Old Credentials:
- Immediately disable/delete old keys in service dashboards
- Don't wait for rotation period
WITHIN 24 HOURS:
-
Audit Recent Access:
- Supabase: Dashboard → Logs → Filter by time range
- Stripe: Dashboard → Logs
- Check for unauthorized API calls
-
Review Recent Commits:
git log --since="2 days ago" --all --oneline # Look for suspicious changes
-
Notify Stakeholders:
- If user data was potentially accessed: Notify users (GDPR/CCPA requirement)
- Document incident in
docs/incidents/YYYY-MM-DD.md
-
Post-Mortem:
- How did credentials get exposed?
- What safeguards failed?
- How to prevent in future?
Signs of Compromise:
- Unexpected database queries in logs
- New admin accounts created
- Unusual API usage patterns
- Failed login attempts from unknown IPs
- Unexpected deploys or code changes
Response:
-
Lock Down Access:
- Enable GitHub 2FA requirement for all team members
- Rotate all production credentials
- Temporarily disable API access if needed
-
Investigate:
- Review Supabase auth logs
- Check GitHub audit log
- Review Vercel/Railway deploy logs
- Check for backdoors in recent commits
-
Document:
- Create incident report
- Timeline of events
- Root cause analysis
- Prevention measures
DO:
- ✅ Use
.env.localfor all local credentials - ✅ Create separate Supabase project for development
- ✅ Run pre-commit hooks before pushing
- ✅ Review your changes before committing (
git diff) - ✅ Use strong, unique passwords for all services
- ✅ Enable 2FA on GitHub, Supabase, Stripe, etc.
- ✅ Keep dependencies updated (
npm update) - ✅ Report security issues privately (see below)
DON'T:
- ❌ Commit
.envfiles (even if "just testing") - ❌ Share credentials via insecure channels
- ❌ Use production database for development
- ❌ Hardcode API keys in source code
- ❌ Disable security checks "temporarily"
- ❌ Bypass pre-commit hooks
- ❌ Share your development
.envwith others
Before approving a PR:
- No hardcoded secrets or API keys
- No
.envfiles added - Authentication checks in place for new API routes
- Database queries use parameterized queries (no SQL injection)
- User input is validated (XSS prevention)
- Rate limiting applied to new endpoints
- No sensitive data logged to console
- Dependencies reviewed (no suspicious packages)
- Tests include security scenarios
- Documentation updated if security-related
Automated Scanning:
# Check for known vulnerabilities
npm audit
# Fix automatically if possible
npm audit fix
# For manual review
npm audit --json > audit-report.jsonGitHub Dependabot:
- Automatically creates PRs for security updates
- Review and merge promptly
- Don't ignore security advisories
Before Adding New Dependencies:
- Check npm package age and downloads
- Review GitHub repository (stars, issues, last commit)
- Check for known vulnerabilities:
npm audit - Review package code if critical (e.g., authentication)
- Prefer well-maintained, popular packages
Found a security vulnerability?
DO NOT:
- ❌ Create a public GitHub issue
- ❌ Post on Slack/Discord
- ❌ Discuss publicly
DO:
- Email security report to: [your-security-email@qalatalk.com]
- Include:
- Description of vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
- Wait for response (within 48 hours)
- We'll work with you on fix and disclosure timeline
Responsible Disclosure:
- We'll acknowledge report within 48 hours
- We'll provide fix timeline within 1 week
- We'll credit you in CHANGELOG (if desired)
- We'll notify affected users if needed
User Rights:
- Right to access their data
- Right to deletion (implemented via API)
- Right to data portability (export feature)
- Right to be informed (privacy policy)
Implementation:
- Data retention: 30 days for chat logs, indefinite for profiles
- Data export: API endpoint
/api/users/export - Data deletion: API endpoint
/api/users/delete - Privacy policy:
/privacypage
User Rights:
- Right to know what data is collected
- Right to delete data
- Right to opt-out of data sales (N/A - we don't sell data)
Implementation:
- Same endpoints as GDPR
- "Do Not Sell" disclosure in privacy policy
What We Store:
- User profiles (name, email, languages, age, gender, country)
- Session history (duration, ratings, quality metrics)
- Vocabulary saved by users
- Reports submitted by users
What We DON'T Store:
- Video call recordings (peer-to-peer only)
- Chat transcripts (deleted after 30 days)
- Payment details (handled by Stripe)
- Biometric data
- Government ID scans
Encryption:
- All data encrypted at rest (Supabase default)
- All connections use TLS/SSL
- Database passwords hashed
- Service role keys never exposed to client
Supabase Logs:
- Failed authentication attempts
- Unusual query patterns
- Rate limit violations
- Database errors
Application Logs:
- API errors (via Sentry)
- User reports
- Session failures
- Translation API quota usage
Infrastructure:
- Deploy failures (GitHub Actions)
- SSL certificate expiration (Vercel auto-renews)
- Uptime monitoring (Vercel Analytics)
Immediate Alerts (Slack/Email):
- Production deployment failures
- Database connection errors
- High error rates (>5% of requests)
- Unusual spikes in traffic
Daily Digest:
- New user signups
- Session completion rates
- Translation quota usage
- Error summary
Before deploying to production:
Infrastructure:
- Separate Supabase project for production
- All production credentials rotated (never use dev credentials)
- Branch protection enabled on main
- GitHub 2FA required for all team members
- Vercel environment variables set correctly
- Railway environment variables set correctly
- SSL certificates active (auto-configured)
- Rate limiting configured (Redis)
- CORS properly configured
Database:
- RLS policies enabled on all tables
- Database backups configured (Supabase Pro)
- Connection pooling enabled
- SSL connections enforced
- Service role key secured (never exposed to client)
Application:
- No console.logs in production code
- Error messages don't leak sensitive info
- All API routes require authentication
- Input validation on all forms
- XSS protection enabled (CSP headers)
- CSRF tokens on state-changing requests
- Rate limiting on authentication endpoints
Monitoring:
- Sentry configured for error tracking
- PostHog configured for analytics (optional)
- Uptime monitoring active
- Alert channels configured
Compliance:
- Privacy policy published
- Terms of service published
- Cookie consent banner (if using cookies)
- Data export API tested
- Data deletion API tested
- GDPR compliance documented
| Role | Contact | Responsibility |
|---|---|---|
| Security Lead | @osiah | Credential rotation, incident response |
| Database Admin | @osiah | Supabase, backups, RLS policies |
| DevOps | @osiah | Vercel, Railway, deployments |
External Services:
- Supabase Support: support@supabase.io
- Vercel Support: support@vercel.com
- Railway Support: team@railway.app
- Stripe Support: support@stripe.com
| Date | Action | Performed By | Reason |
|---|---|---|---|
| YYYY-MM-DD | Credential rotation | @osiah | Quarterly schedule |
| YYYY-MM-DD | Branch protection enabled | @osiah | Security hardening |
| YYYY-MM-DD | Developer offboarded | @osiah | Team change |
Maintain this log for compliance and incident response.
- OWASP Top 10 - Common web vulnerabilities
- Supabase Security - Platform security guide
- Next.js Security - Framework security
- GitHub Security - Repository security
Last Updated: 2025-09-29 Review Schedule: Quarterly Next Review: 2025-12-29