Learn

Navigate through learn topics

Security Leak Prevention

Preventing API key leaks and setting up detection systems before they become incidents

Last updated: 8/15/2025

Prevention is better than cure when it comes to API key leaks. Here's how to set up systems that stop secrets from escaping in the first place.

Common Leak Sources

Git Commits (Most Common)

# Dangerous patterns that often get committed
echo "SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIs..." > .env
git add .env  # NEVER DO THIS

# Safe patterns
echo ".env*" >> .gitignore
echo "*.env" >> .gitignore
git add .gitignore  # This is safe

CI/CD Logs

# Bad: secrets in build logs
echo "Connecting with key: $SUPABASE_SERVICE_ROLE_KEY"

# Good: hide sensitive values
echo "Connecting with key: ${SUPABASE_SERVICE_ROLE_KEY:0:8}..."

Development Tools

// Bad: secrets in browser console
console.log('Config:', {
  supabaseKey: process.env.SUPABASE_SERVICE_ROLE_KEY
});

// Good: mask or omit secrets
console.log('Config:', {
  supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
  keyLength: process.env.SUPABASE_SERVICE_ROLE_KEY?.length
});

.gitignore Setup

Comprehensive .gitignore

# Environment variables
.env
.env.*
.env.local
.env.development
.env.staging
.env.production
*.env

# OS files
.DS_Store
Thumbs.db

# IDE files
.vscode/settings.json
.idea/
*.swp
*.swo

# Dependencies
node_modules/
.pnpm-debug.log*

# Build outputs
.next/
dist/
build/

# Runtime files
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

Environment File Template

Create .env.example (safe to commit):

# .env.example
# Copy this to .env.local and fill in real values

# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key_here
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key_here

# Other services
STRIPE_SECRET_KEY=sk_test_...
SENDGRID_API_KEY=SG...

Automated Detection Tools

Gitleaks (Local Scanning)

Install and run locally:

# Install gitleaks
brew install gitleaks

# Scan current repository
gitleaks detect --verbose --redact

# Scan git history
gitleaks detect --verbose --redact --log-opts="--all"

# Pre-commit hook
gitleaks protect --verbose --redact --staged

Pre-commit Hooks

Setup with Husky:

# Install husky
npm install --save-dev husky

# Add pre-commit hook
npx husky add .husky/pre-commit "gitleaks protect --staged"

Or manual git hook in .git/hooks/pre-commit:

#!/bin/sh
# Prevent commits with secrets

if command -v gitleaks >/dev/null 2>&1; then
    gitleaks protect --staged
    if [ $? -ne 0 ]; then
        echo "❌ Secrets detected in staged files"
        exit 1
    fi
fi

# Additional patterns check
if git diff --cached --name-only | xargs grep -l "sk_live_\|sk_test_\|eyJhbGciOiJIUzI1NiIs"; then
    echo "Potential secrets found in staged files"
    exit 1
fi

GitHub Secret Scanning

Enable in repository settings:

  1. Settings (Code Security) (Secret Scanning)
  2. Enable "Secret scanning"
  3. Enable "Push protection" (blocks pushes with secrets)
  4. Configure custom patterns for your specific secrets

Custom patterns for Supabase keys:

# Service role keys (high entropy JWT-like strings)
eyJ[A-Za-z0-9+/=]{100,}

# Supabase project URLs
https://[a-z]{20}\.supabase\.co

Development Workflow Security

Environment Loading

// utils/env-check.js
const validateEnvironment = () => {
  const required = [
    'NEXT_PUBLIC_SUPABASE_URL',
    'NEXT_PUBLIC_SUPABASE_ANON_KEY'
  ];
  
  const serverRequired = [
    'SUPABASE_SERVICE_ROLE_KEY'
  ];
  
  // Check public vars
  const missing = required.filter(key => !process.env[key]);
  if (missing.length > 0) {
    throw new Error(`Missing public env vars: ${missing.join(', ')}`);
  }
  
  // Check server vars (only on server)
  if (typeof window === 'undefined') {
    const missingServer = serverRequired.filter(key => !process.env[key]);
    if (missingServer.length > 0) {
      console.warn(`Missing server env vars: ${missingServer.join(', ')}`);
    }
  }
  
  // Warn about potential mistakes
  required.forEach(key => {
    const value = process.env[key];
    if (value && value.includes('your_') || value.includes('example')) {
      console.warn(`⚠️ ${key} looks like a placeholder value`);
    }
  });
};

// Call during app initialization
validateEnvironment();

Safe Configuration Loading

// config/supabase.js
const getConfig = () => {
  const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
  const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
  
  // Validate format
  if (!url?.startsWith('https://')) {
    throw new Error('Invalid Supabase URL format');
  }
  
  if (!anonKey?.startsWith('eyJ')) {
    throw new Error('Invalid anon key format');
  }
  
  // Warn about common mistakes
  if (url.includes('your-project')) {
    console.warn('Supabase URL looks like a placeholder');
  }
  
  return { url, anonKey };
};

export const config = getConfig();

Team Security Practices

Onboarding Checklist

## New Developer Security Setup

- Install gitleaks: `brew install gitleaks`
- Setup pre-commit hooks: `npx husky add .husky/pre-commit "gitleaks protect --staged"`
- Copy `.env.example` to `.env.local`
- Get environment variables from team lead (never via Slack/email)
- Verify `.env.local` is in `.gitignore`
- Test local setup without committing secrets
- Review security guidelines document

Secret Sharing Protocol

## How to Share Secrets Safely

### Never Use
- Slack messages
- Email
- Text files in shared drives
- Screenshots
- Voice calls (someone might record)

### Safe Methods
- Password managers (1Password, Bitwarden)
- Encrypted notes apps
- In-person handoff
- Secure secret sharing services (with expiration)

Regular Security Reviews

#!/bin/bash
# scripts/security-audit.sh

echo "πŸ” Running security audit..."

# Check for secrets in codebase
echo "Checking for potential secrets..."
gitleaks detect --verbose --redact

# Check gitignore patterns
echo "Validating .gitignore..."
if grep -q "\.env" .gitignore; then
    echo ".env patterns found in .gitignore"
else
    echo "Missing .env patterns in .gitignore"
fi

# Check for hardcoded URLs/keys
echo "Checking for hardcoded secrets..."
grep -r "supabase\.co" . --exclude-dir=node_modules --exclude-dir=.git | grep -v ".env.example"
grep -r "eyJ[A-Za-z0-9]" . --exclude-dir=node_modules --exclude-dir=.git | grep -v ".env.example"

echo "πŸ” Audit complete"

Recovery Planning

Incident Response Preparation

## Secret Leak Response Plan

### Immediate (0-15 minutes)
1. Rotate exposed keys in Supabase dashboard
2. Remove keys from CI/CD environment variables
3. Deploy with temporary/blank values if needed

### Short-term (15-60 minutes)
1. Update all environments with new keys
2. Remove secrets from git history
3. Force-push cleaned repository
4. Audit logs for suspicious activity

### Follow-up (1-24 hours)
1. Review how leak occurred
2. Update prevention measures
3. Document lessons learned
4. Train team on new procedures

Key Rotation Schedule

// utils/key-rotation-reminder.js
const checkKeyAge = () => {
  const keyCreatedDate = process.env.SUPABASE_KEY_CREATED_DATE;
  
  if (!keyCreatedDate) {
    console.warn('⚠️ No key creation date set - consider rotating keys');
    return;
  }
  
  const created = new Date(keyCreatedDate);
  const now = new Date();
  const ageInDays = (now - created) / (1000 * 60 * 60 * 24);
  
  if (ageInDays > 90) {
    console.warn(`πŸ”‘ Supabase keys are ${Math.floor(ageInDays)} days old - consider rotation`);
  }
};

// Run during app startup in development
if (process.env.NODE_ENV === 'development') {
  checkKeyAge();
}

Monitoring and Alerts

Log Analysis

# Check CI logs for secrets (run periodically)
grep -i "supabase\|key\|secret\|token" build-logs.txt | grep -v "REDACTED"

GitHub Repository Settings

  1. Enable vulnerability alerts
  2. Enable dependency security updates
  3. Require signed commits (optional but recommended)
  4. Branch protection rules for main/production branches
  5. Require pull request reviews before merging

Prevention requires building security into your development workflow, not just reacting to leaks after they happen. Start with these tools and practices from day one of your project.

Related Topics

Continue building your security knowledge: