Security Architecture

PULSE security model and implementation

Security Architecture

PULSE implements defense-in-depth security across all layers.

Authentication & Authorization

API Key Management

// API key format: pulse_prod_xxxxx
const API_KEY_PREFIX = 'pulse_prod_'
const API_KEY_LENGTH = 32  // + prefix

// Key rotation
// 1. Generate new key
// 2. Deploy with both keys
// 3. Clients update
// 4. Revoke old key

Authentication Flow

1. Client sends: Authorization: Bearer pulse_prod_xxxxx
2. Server checks KV cache
3. If miss: Query D1, cache result (60s TTL)
4. Verify key belongs to site_id
5. Return 401 if invalid

Session Management

// HTTPOnly cookies
response.headers.set('Set-Cookie',
  `session=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`
)

// SessionID validation on every request
const session = await validateSession(sessionId)

Network Security

HTTPS/TLS

CORS Configuration

const origin = request.headers.get('Origin')
const ALLOWED_ORIGINS = [
  'https://app.example.com',
  'https://analytics.example.com'
]

if (!ALLOWED_ORIGINS.includes(origin)) {
  return new Response('Forbidden', { status: 403 })
}

Rate Limiting

Per-IP rate limits:

// Auth endpoint: 10 requests/minute
const limitResult = await env.RATE_LIMITER.limit({
  key: `${clientIp}/auth`
})

if (!limitResult.success) {
  return new Response(JSON.stringify({
    success: false,
    error: 'Rate limit exceeded'
  }), { status: 429 })
}

Data Protection

Encryption at Rest

Encryption in Transit

Data Masking

Sensitive data handling:

// Password hashing
const hash = await crypto.subtle.digest('SHA-256', password)

// PII redaction
const redactedEmail = '***@example.com'

// Token masking in logs
console.log(`Token: ${token.substring(0, 8)}...`)

Input Validation

Strict Validation

// Always validate at boundary
const schema = z.object({
  email: z.string().email(),
  age: z.number().int().min(0).max(150)
})

const validated = schema.parse(input)

SQL Injection Prevention

// Good: Parameterized queries
db.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first()

// Bad: String concatenation
db.prepare(`SELECT * FROM users WHERE id = ${userId}`).first()

XSS Prevention

// Sanitize HTML output
const sanitized = DOMPurify.sanitize(userContent)

// Use CSP headers
response.headers.set('Content-Security-Policy',
  "default-src 'self'; script-src 'self' 'unsafe-inline'"
)

OWASP Top 10 Protection

VulnerabilityProtection
InjectionParameterized queries, input validation
Broken AuthAPI key validation, rate limiting, HTTPOnly cookies
Sensitive DataEncryption at rest + transit, masking
XML External EntitiesJSON only, no XML parsing
Broken Access ControlSite-level isolation, row-level security
Security MisconfigurationSecrets via environment, no defaults
XSSHTML sanitization, CSP headers
Insecure DeserializationJSON validation, no unsafe parsing
Using Components with Known VulnsRegular npm audit, dependency updates
Insufficient LoggingRequest logging, audit trail

GDPR Compliance

Data Retention

// Automatic deletion after retention period
DELETE FROM events
WHERE created_at < NOW() - INTERVAL '90 days'

Right to Deletion

// User data deletion
DELETE FROM events WHERE user_id = ?
DELETE FROM users WHERE user_id = ?
DELETE FROM cohort_members WHERE user_id = ?

Data Portability

// Export user data
SELECT * FROM events WHERE user_id = ?
ORDER BY timestamp DESC

Secrets Management

No Hardcoded Secrets

// Bad
const API_KEY = "sk-proj-xxxxx"

// Good
const API_KEY = process.env.API_SECRET
if (!API_KEY) throw new Error('API_SECRET not configured')

Secret Rotation

# Update secret
wrangler secret put API_SECRET --env production

# Verify new secret works
# Then revoke old secret
wrangler secret delete API_SECRET_OLD

Audit Logging

Track all access:

const auditLog = {
  timestamp: Date.now(),
  userId: user.id,
  action: 'api_call',
  endpoint: path,
  status: response.status,
  ipAddress: clientIp
}

await logAudit(auditLog)

Third-Party Security

Dependency Management

# Check for vulnerabilities
npm audit

# Update dependencies
npm update

# Review new versions
npm list

Supply Chain Security

Production Hardening

Environment Isolation

# Development
[env.development]
vars = { DEBUG = "true" }

# Production
[env.production]
vars = { DEBUG = "false" }

Error Handling

Never expose sensitive info:

// Bad
return { error: "Database connection failed: " + err.message }

// Good
return { error: "An error occurred. Please try again." }
console.error("DB Error:", err)  // Log details separately

Health Checks

Verify security posture:

curl https://api.example.com/health/ready
# Checks:
# - Database connectivity
# - KV connectivity
# - API secret configured
# - TLS working

Security Best Practices

  1. Principle of Least Privilege

    • Grant minimum required permissions
    • API keys per-site, not global
  2. Defense in Depth

    • Multiple security layers
    • Fail securely
  3. Continuous Monitoring

    • Log all access
    • Alert on anomalies
  4. Regular Updates

    • Patch dependencies
    • Update runtime
  5. Incident Response

    • Have runbook
    • Practice procedures

Security Checklist

Next Steps

Last updated: April 3, 2026