Layers
Security

Security Guide

Comprehensive security documentation for the Layers API Gateway, including implemented protections, known concerns, and hardening recommendations for production deployments.

Living Document

This security guide is maintained as a living document. As new security concerns are discovered or mitigations are implemented, this page will be updated. Last updated: 2026-01-24.

Security Architecture Overview#

Layers implements a multi-layered security approach across authentication, authorization, rate limiting, and cost controls. However, as an API gateway handling sensitive operations and billing, ongoing security hardening is critical.

What We Do Well

  • API keys hashed before storage (SHA256)
  • Stripe webhook signature verification
  • Tier-based rate limiting
  • Pre-flight credit checks
  • Session cookies with httpOnly, secure, SameSite=Lax

Areas Needing Attention

  • Service role key bypasses Row Level Security (RLS)
  • Test mode authentication bypass with weak defaults
  • No CORS restrictions on API endpoints
  • PII (emails) logged in production
  • No request size limits

Critical Security Concerns#

1. Row Level Security (RLS) Bypass#

High Priority

The Supabase service role key bypasses all Row Level Security policies. This means application code is the only protection preventing users from accessing other users' data.

Current State:

// lib/supabase/client.ts:8
// Create a Supabase server client with service role key (bypasses RLS)
export function createServerClient(): SupabaseClient {
  serverClient = createClient(url, serviceKey, { /* ... */ });
  return serverClient;
}

Risk:

  • A bug in user_id filtering could expose all user data
  • SQL injection vulnerabilities become critical
  • No defense-in-depth if authorization logic fails

Mitigation Steps:

  1. Enable RLS on all tables:
    -- In Supabase SQL Editor
    ALTER TABLE users ENABLE ROW LEVEL SECURITY;
    ALTER TABLE api_keys ENABLE ROW LEVEL SECURITY;
    ALTER TABLE credit_balances ENABLE ROW LEVEL SECURITY;
    ALTER TABLE usage_logs ENABLE ROW LEVEL SECURITY;
    ALTER TABLE credit_transactions ENABLE ROW LEVEL SECURITY;
  2. Create policies for each table:
    -- Users can only see their own data
    CREATE POLICY "Users can view own data"
      ON credit_balances FOR SELECT
      USING (auth.uid() = user_id);
    
    CREATE POLICY "Users can update own data"
      ON credit_balances FOR UPDATE
      USING (auth.uid() = user_id);
  3. Audit all queries: Search codebase for database queries and verify each includes proper user_id filtering
  4. Use anon key where possible: For read operations, consider using the anon key instead of service role

2. Test Mode Authentication Bypass#

High Priority

Test mode uses a hardcoded default secret that's visible in the source code. If deployed without proper configuration, this could allow complete authentication bypass.

Current State:

// lib/middleware/auth.ts:6
const TEST_MODE_SECRET = process.env.LAYERS_TEST_SECRET || 'layers-integration-test-2026';

// Anyone who sends this header bypasses auth:
// X-Layers-Test-Mode: layers-integration-test-2026

Risk:

  • Public GitHub repo exposes the default secret
  • Attackers can bypass all authentication and rate limiting
  • Could be used to drain credits or access user data

Mitigation Steps:

  1. Remove hardcoded default:
    // Require the environment variable
    const TEST_MODE_SECRET = process.env.LAYERS_TEST_SECRET;
    if (!TEST_MODE_SECRET) {
      throw new Error('LAYERS_TEST_SECRET required for test mode');
    }
  2. Disable in production:
    function isTestMode(headers?: Headers): boolean {
      // Never allow test mode in production
      if (process.env.NODE_ENV === 'production') {
        return false;
      }
      // ... rest of test mode checks
    }
  3. Use cryptographically random secret: Generate with openssl rand -base64 48
  4. Consider IP allowlisting: Only allow test mode from specific IPs (CI servers)

3. Missing CORS Configuration#

Current State:

API endpoints under /api/v1/* have no CORS restrictions. Any website can call your API.

Risk:

  • If a user's API key leaks (e.g., committed to GitHub), any site can use it
  • Malicious sites could make requests on behalf of users
  • Cross-origin attacks become easier

Mitigation Steps:

// In app/api/v1/chat/route.ts (and other endpoints)
export async function OPTIONS() {
  return new Response(null, {
    status: 204,
    headers: {
      'Access-Control-Allow-Origin': process.env.ALLOWED_ORIGINS || 'https://layers.hustletogether.com',
      'Access-Control-Allow-Methods': 'POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Authorization, Content-Type',
      'Access-Control-Max-Age': '86400', // 24 hours
    },
  });
}

// Add to response headers in POST handler
headers: {
  ...getRateLimitHeaders(rateLimitResult),
  'Access-Control-Allow-Origin': process.env.ALLOWED_ORIGINS || 'https://layers.hustletogether.com',
}

Medium Priority Concerns#

4. Logging Sensitive Data#

Found in:

  • [app/auth/callback/route.ts:51](app/auth/callback/route.ts#L51) - Logs user emails
  • [app/api/v1/chat/route.ts:357](app/api/v1/chat/route.ts#L357) - Exposes error details to users

Risk:

  • GDPR/privacy violations
  • Stack traces might leak implementation details
  • Logs become a security liability if breached

Mitigation:

// Bad - logs PII
console.log('[OAuth] User:', data?.user?.email);

// Good - logs anonymized ID
console.log('[OAuth] User authenticated:', data?.user?.id);

// Bad - exposes details to user
return NextResponse.json(
  { error: 'Internal server error', details: String(error) },
  { status: 500 }
);

// Good - generic message, detailed server log
console.error('[API Error]', error);
return NextResponse.json(
  { error: 'Internal server error', request_id: requestId },
  { status: 500 }
);

5. SHA256 for API Key Hashing#

While better than plain text, SHA256 is not ideal for hashing secrets due to its speed (enables rainbow table attacks).

Current State:

// lib/supabase/client.ts:46
export function hashApiKey(key: string): string {
  return createHash('sha256').update(key).digest('hex');
}

Recommendation:

import bcrypt from 'bcrypt';

export async function hashApiKey(key: string): Promise<string> {
  return bcrypt.hash(key, 12); // 12 rounds = good balance
}

// Note: This makes key lookups slower, but more secure
// Consider caching valid keys in Redis for performance

6. Demo Mode Fallback#

If Supabase isn't configured, auth middleware returns a mock user. This could accidentally run in production.

Mitigation:

if (!isSupabaseConfigured()) {
  if (process.env.NODE_ENV === 'production') {
    throw new Error('Supabase must be configured in production');
  }
  // Demo mode only for local dev
  console.warn('Running in demo mode - dev only');
  return mockUser;
}

Lower Priority Improvements#

7. Request Size Limits#

Add body size limits to prevent abuse:

// next.config.js
module.exports = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
};

8. Input Sanitization#

Consider adding:

  • Maximum message length (e.g., 100,000 chars)
  • Maximum messages array length (e.g., 100 messages)
  • Content filtering for known attack patterns
  • Rate limiting on specific model + user combinations

9. Maximum Spend Limits#

const MAX_CREDITS_PER_REQUEST = 100;  // ~$1.00
const MAX_CREDITS_PER_HOUR = 1000;     // ~$10.00

if (estimated > MAX_CREDITS_PER_REQUEST) {
  return NextResponse.json(
    {
      error: 'Request exceeds maximum cost',
      max_credits: MAX_CREDITS_PER_REQUEST,
      estimated_credits: estimated
    },
    { status: 400 }
  );
}

Environment Variable Security#

VariableRisk LevelIf Compromised
SUPABASE_SERVICE_ROLE_KEYCriticalFull database access, can read/write all data
AI_GATEWAY_API_KEYCriticalCan make expensive AI requests on your account
STRIPE_SECRET_KEYCriticalCan charge customers, access payment info
STRIPE_WEBHOOK_SECRETHighCan forge billing webhooks
LAYERS_TEST_SECRETHighBypass authentication completely
NEXT_PUBLIC_SUPABASE_ANON_KEYMediumLimited by RLS, but could abuse rate limits

Best Practices:

  1. Never commit .env files to git
  2. Use Vercel's encrypted environment variables
  3. Different keys for dev/staging/production
  4. Rotate keys regularly (quarterly minimum)
  5. Monitor for leaked keys using GitHub secret scanning
  6. Store production secrets in a password manager (1Password, Bitwarden)

Security Monitoring & Alerts#

Implement Anomaly Detection#

Monitor for suspicious patterns:

PatternThresholdAction
Usage spike10x normal hourly usageAlert admin, temporary rate limit
Failed auth attempts50 from same IP in 5 minBlock IP temporarily
Rapid key creation5+ keys in 1 hourFlag account for review
Credit refund abuseMultiple refunds same userManual review required
High-cost modelsOpus/O1 > $100/dayAlert user and admin

Audit Logging#

Log security-relevant events to a separate audit table:

CREATE TABLE audit_logs (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  timestamp TIMESTAMPTZ DEFAULT NOW(),
  user_id UUID,
  event_type TEXT NOT NULL, -- 'key_created', 'tier_changed', 'auth_failed', etc.
  ip_address INET,
  user_agent TEXT,
  metadata JSONB,
  severity TEXT -- 'info', 'warning', 'critical'
);

Events to log:

  • API key creation/deletion
  • Failed authentication attempts
  • Credit purchases and refunds
  • Subscription tier changes
  • Rate limit violations
  • Unusually expensive requests

Security Hardening Checklist#

Enable RLS on all tables

Create policies for user_id filtering

Remove test mode default secret

Require LAYERS_TEST_SECRET env var

Disable test mode in production

Check NODE_ENV before allowing bypass

Add CORS configuration

Restrict origins to your domains

Remove PII from logs

Use user IDs instead of emails

Disable demo mode in production

Throw error if Supabase not configured

Audit all database queries

Verify user_id filtering on every query

Add request size limits

Set 1MB limit in Next.js config

Implement max spend limits

Prevent >$1 per request, >$10 per hour

Upgrade to bcrypt for API keys

Better than SHA256 for secret hashing

Set up anomaly detection

Alert on 10x usage spikes

Implement audit logging

Track key creation, auth failures, tier changes

Rotate all secrets

New keys for LAYERS_TEST_SECRET, webhooks

Enable GitHub secret scanning

Detect accidental key commits

Set up Dependabot

Auto-update vulnerable dependencies

Incident Response Plan#

If an API Key Leaks#

  1. Immediately deactivate the key in dashboard
  2. Check usage_logs for unauthorized usage
  3. Notify affected user
  4. Review how the leak occurred (committed to git, public logs, etc.)
  5. Generate replacement key for user
  6. If in git history: use BFG Repo Cleaner to remove from history

If Database Access Compromised#

  1. Immediately rotate SUPABASE_SERVICE_ROLE_KEY
  2. Force logout all users (invalidate sessions)
  3. Audit database for unauthorized changes
  4. Check usage_logs for anomalous activity
  5. Notify affected users per GDPR requirements
  6. Review and strengthen RLS policies
  7. Enable database audit logging
  8. Consider incident response service (e.g., Stripe incident response)

If Billing Abuse Detected#

  1. Temporarily suspend affected API keys
  2. Contact user via email
  3. Review usage_logs for patterns
  4. Implement stricter rate limits for account
  5. Consider refund policy (case-by-case)
  6. Update anomaly detection to catch similar patterns

Compliance Considerations#

GDPR (EU Users)#

  • Right to access: Users can export their data via dashboard
  • Right to deletion: Delete user accounts and all associated data
  • Data minimization: Only collect necessary data (email, usage)
  • Breach notification: Must notify within 72 hours of discovery
  • Logging PII: Remove emails from production logs

PCI DSS (Credit Cards)#

Layers uses Stripe for payment processing, which is PCI Level 1 certified. We never handle raw credit card data. Stripe handles all card storage and processing.

SOC 2 (Enterprise Customers)#

If targeting enterprise customers, consider SOC 2 Type II certification:

  • Implement all items in security checklist
  • Document security policies and procedures
  • Regular penetration testing
  • Vendor risk assessments (Anthropic, OpenAI, Supabase, Stripe)
  • Incident response procedures
  • Employee security training

Additional Resources#

ResourceLink
OWASP Top 10owasp.org/top-ten ↗
Supabase Securitysupabase.com/docs/security ↗
Next.js Security Headersnextjs.org/docs/headers ↗
Stripe Securitystripe.com/docs/security ↗
GDPR Compliancegdpr.eu/checklist ↗

Related Documentation

Questions or security concerns? Please email alfonso@mirrorfactory.dev for responsible disclosure of security vulnerabilities.