Security Architecture
Traces is designed with security as a first principle, especially important for handling sensitive forensic data.
Security Principles
- No secrets in database - Credentials stored only in Doppler (only a secret reference is persisted)
- Immutable audit trail - Chain of custody events are append-only
- Independent hash validation - Dual-library hashing (Node
crypto+@noble/hashes) - SSRF protection - Every outbound request to an analyst/connector-controlled URL is validated before each hop
- Authenticated APIs - All sensitive routes (including connector reads) require a Clerk session
- Encrypted storage - R2 server-side encryption with versioning
Database-enforced row-level security (RLS) is planned but not yet active. Authorization is currently enforced in the application layer (Clerk session + role checks in the API route handlers).
Authentication
User Authentication (Clerk)
- Multi-factor authentication supported
- OAuth2 providers (Google, Microsoft)
- Session management with secure tokens
- Webhook for user events
API Authentication
- JWT tokens for API access
- Token validation on every request
- Role-based access control (RBAC)
Authorization
Role-Based Access Control
| Role | Capabilities |
|---|---|
| Customer | Own collections, credentials, profile |
| Analyst | All collections, connectors, sign-offs |
| Admin | All analyst + user management |
Application-Layer Authorization
Authorization is enforced in the API route handlers using the Clerk session and the user's role. For example, GET /api/connectors/[id] (which returns sensitive connector internals such as auth_config and runtime parameters) calls auth() and returns 401 when there is no authenticated user.
Row-Level Security (Planned)
Database-enforced RLS is a planned future layer. The intended policies look like:
-- Customers can only see their own collections
CREATE POLICY customer_collections ON collections
FOR ALL TO customer_role
USING (customer_id = current_user_customer_id());
Credential Security
Storage
- Credentials NEVER stored in the application database
- Only a secret reference (the
secret_arncolumn — a legacy name) is stored in the DB - Stored in Doppler, encrypted application-side with AES-256-GCM (
apps/web/src/lib/secrets)
Access
- All access logged to credential_access_logs
- Just-in-time retrieval during collection
- Credentials cached only in memory
- Secure deletion (cryptographic overwrite)
Lifecycle
Created → Validated → Used → Revoked/Expired
│
├── All access logged
└── Encryption at rest
Data Encryption
In Transit
- TLS 1.3 for all connections
- Certificate pinning where possible
- Secure WebSocket for real-time
At Rest
- PostgreSQL encryption (Supabase managed)
- R2 server-side encryption
- Credentials encrypted application-side (AES-256-GCM) before storage in Doppler
Hash Validation
Dual-Library Approach
Collected data is hashed with two independent implementations so a bug in one cannot silently corrupt the integrity record (apps/worker/src/collectors/api-caller.ts):
- Primary hash via Node's built-in
crypto(createHash("sha256")) - Independent validation hash via
@noble/hashes(sha256+bytesToHex)
When both agree, the record is marked validated (response_body_hash_validated on api_logs, sha256_hash_validated on collected_files). If @noble/hashes cannot be loaded, the worker falls back to the crypto hash and logs a warning.
Hash Chain
Every API response is hashed:
- Request body hash (for POST/PUT)
- Response body hash
- Validated response body hash
Audit Logging
Chain of Custody Events
Immutable log of every action:
- Collection creation
- Status changes
- Analyst assignments
- Sign-offs
- Delivery
Credential Access Logs
Every credential access recorded:
- Who accessed
- When accessed
- Access type (read, validate, use)
- Success/failure
API Logs
Comprehensive request logging:
- Sanitized headers (no tokens)
- Response codes
- Timing information
- Error details
SSRF Protection
Both the web app and the worker make outbound HTTP requests to analyst- and connector-controlled URLs (auth testing, token exchange, mTLS cert requests, endpoint tests, and the collection run itself). Without guarding, an authenticated analyst could point those requests at cloud metadata (169.254.169.254), localhost, or internal services and exfiltrate data — a classic SSRF.
Shared core guard: packages/utils/src/ssrf.ts (assertUrlAllowed, checkUrlAllowed, isBlockedIp, SsrfError). It resolves the target host and blocks requests to:
- loopback (
127.0.0.0/8,::1) - link-local / metadata (
169.254.0.0/16incl.169.254.169.254,fe80::/10) - RFC-1918 private ranges (
10/8,172.16/12,192.168/16) and CGNAT (100.64.0.0/10) - the equivalent IPv6 ranges (ULA, mapped-private, etc.)
DNS is resolved and every answer checked, so a hostname that resolves to a private address ("DNS rebinding"-style) is also blocked.
safeFetch (apps/web/src/lib/security/ssrf-guard.ts and the worker's apps/worker/src/lib/safe-fetch.ts) is a drop-in fetch replacement that validates the target before every request and re-validates each redirect hop (a public host can 302 to 169.254.169.254). It follows redirects manually (max 5 hops) so each Location is checked before being requested. Raw node:https requests (mTLS) call assertUrlAllowed directly since they don't auto-follow redirects.
The guard can be toggled via the TRACES_SSRF_GUARD environment variable (it is disabled in the web vitest test environment). Scheme enforcement still applies even when the private-network checks are disabled.
Network Security
Firewall Rules
- Restrict database access to application
- Worker communicates only with required services
- No direct internet exposure for internal services
Rate Limiting
- Per-user rate limits
- Platform-specific rate limiting
- DDoS protection via Cloudflare
Secure Development
Code Security
- Dependency scanning
- Security linting
- Regular updates
Secret Management
- No secrets in code
- Environment variables for config
- Doppler for sensitive credential data
Compliance Considerations
Data Handling
- Data minimization
- Purpose limitation
- Retention policies
Geographic
- Data residency options
- Regional deployment
Regulatory
- Designed for legal/compliance use
- Audit trail for investigations
- Chain of custody support
Incident Response
Detection
- Anomaly monitoring
- Failed authentication alerts
- Unusual access patterns
Response
- Credential revocation
- Session invalidation
- Incident logging
Security Checklist
When deploying:
- All secrets in environment variables
- HTTPS enforced
- Database connections use SSL
- R2 bucket not publicly accessible
- Clerk webhook verification enabled
- Rate limiting configured
- CORS policies correct
- Security updates applied