Security & Privacy
Security at Frequency is not a bolt-on — it’s built into the architecture through classification systems, automated quality gates, and middleware that runs on every request.
PII Classification
Every schema field that contains personal data must be classified using the x-pii extension. This enables automated compliance reporting, encryption policies, and data retention enforcement.
Classification Levels
Highly Sensitive
Data that could cause severe harm if exposed. Requires encryption at rest and in transit. Strict access controls and audit logging.
Examples: SSN, financial account numbers, health records, passwords
Sensitive
Personally identifiable information. Requires encryption at rest. Subject to GDPR/CCPA data subject requests.
Examples: Email address, phone number, mailing address, date of birth
Quasi-Identifiable
Data that could identify a person when combined with other data. Requires anonymization in analytics and exports.
Examples: IP address, device ID, browser fingerprint, zip code
None
Non-personal data. No special handling required.
Examples: Product names, public settings, aggregate counts
PII Schema Extension
{
"customer_email": {
"type": "string",
"format": "email",
"x-pii": {
"level": "sensitive",
"category": "email",
"retention": "2 years",
"encryption": "at-rest",
"anonymization": "hash",
"gdprField": true,
"ccpaField": true
}
}
}Available Categories
email, name, ssn, financial, health, address, phone, dob, ip_address, device_id, biometric
API Security Tiers
See API Standards for full details on the three-tier model:
| Tier | Path | Auth | Rate Limit |
|---|---|---|---|
| Internal | /api/internal/* | Service role key | None |
| Authenticated | /api/v1/* | User session | 100 req/min |
| Public | /api/public/* | None | 10 req/min |
Middleware Security
Every request passes through security middleware:
Content Security Policy (CSP)
The middleware configures a strict CSP that prevents XSS, clickjacking, and data injection:
addSecurityHeaders(response);
// Sets:
// Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-...'; ...
// Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
// X-Frame-Options: DENY
// X-Content-Type-Options: nosniff
// Referrer-Policy: strict-origin-when-cross-originRequest Tracing
Every request gets a UUID for end-to-end tracing:
addRequestId(request);
// Adds: x-request-id header
// Available in: logs, error reports, API responsesMaintenance Mode
Emergency circuit breaker for the entire application:
MAINTENANCE_MODE=true
MAINTENANCE_BYPASS_KEY=secret-key-for-adminsQuality Gates
Automated security checks run on every change through the AI Drivers system.
VALIDITUS — Security Gate (Blocking)
This gate blocks merges if violations are found:
| Check | Threshold | What It Catches |
|---|---|---|
| Critical findings | 0 allowed | Hardcoded secrets, SQL injection |
| High findings | 0 allowed | Missing RLS policies, XSS vectors |
| Medium findings | ≤3 allowed | Missing input validation, verbose errors |
Triggers: Any change to security-related code, x-pii fields, RLS policies, or auth logic.
GATED — Code Review Gate (Blocking)
Required human approvals before merge:
| Change Type | Approvals Required |
|---|---|
| Documentation only | 1 |
| Small changes | 1 |
| Architecture changes | 2 |
Checklist: Code quality, type safety, testing, performance, security.
Environment Variables
Secrets Management
# ✅ CORRECT — use environment variables
const key = process.env.SUPABASE_SERVICE_ROLE_KEY;
# ❌ WRONG — never hardcode secrets
const key = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';Required Variables
| Variable | Scope | Purpose |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | Client + Server | Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Client + Server | Public API key |
SUPABASE_SERVICE_ROLE_KEY | Server only | Admin access (never expose to client) |
Optional Variables
| Variable | Scope | Purpose |
|---|---|---|
NEXT_PUBLIC_GA_ID | Client | Google Analytics |
FLAGS_SECRET | Server | Vercel feature flags |
MAINTENANCE_MODE | Server | Enable maintenance page |
MAINTENANCE_BYPASS_KEY | Server | Bypass maintenance mode |
LOG_LEVEL | Server | Server logging level |
NEXT_PUBLIC_LOG_LEVEL | Client | Client logging level |
Logging
import { logger, createLogger } from '@/core/lib/logger';
// General logging
logger.info('Operation completed', { userId, action: 'invoice_created' });
logger.error('Operation failed', new Error('reason'), { requestId });
// Scoped logger
const authLogger = createLogger({ context: 'auth' });
authLogger.warn('Failed login attempt', { email, ip });Rules:
- Never log PII at
infolevel — usedebugwith appropriate guards - Always include
requestIdin error logs - Log level controlled via environment variables
Security Checklist
Before every PR, verify:
- No hardcoded secrets or API keys
- All user input validated with Zod
- PII fields have
x-piiclassification - API routes use appropriate security tier
- RLS policies cover new tables
- Error messages don’t expose internal details
- CORS configured for the correct origins
- Rate limiting applied to public endpoints