Security Overview
Security Overview
Security Overview
Formic employs a defense-in-depth security model with multiple independent layers of protection. Every form submission passes through a pipeline of security checks before it is stored and delivered.
Security Pipeline
Incoming Request
│
▼
┌─────────────────┐
│ TLS/HTTPS │ ← Terminated at Caddy reverse proxy
│ (Transport) │
└─────────────────┘
│
▼
┌─────────────────┐
│ API Key Auth │ ← X-API-Key header verified via bcrypt
│ (Identity) │
└─────────────────┘
│
▼
┌─────────────────┐
│ Turnstile CAPT │ ← Cloudflare Turnstile anti-bot check
│ (Anti-Bot) │
└─────────────────┘
│
▼
┌─────────────────┐
│ Origin Check │ ← Per-form allowed origins allow-list
│ (CORS Policy) │
└─────────────────┘
│
▼
┌─────────────────┐
│ Payload Limit │ ← 2MB maximum request body
│ (Size Control) │
└─────────────────┘
│
▼
┌─────────────────┐
│ JSON Schema │ ← Structural validation against form schema
│ (Validation) │
└─────────────────┘
│
▼
┌─────────────────┐
│ XSS Sanitize │ ← HTML entity escape, Unicode normalize
│ (Data Clean) │
└─────────────────┘
│
▼
┌─────────────────┐
│ Rate Limit │ ← Per-form + global rate limits (Redis)
│ (Abuse Control)│
└─────────────────┘
│
▼
Delivered
Feature Summary
| Feature | Description | Details |
|---|---|---|
| Authentication | API key via X-API-Key header | bcrypt-hashed keys, anti-enumeration (401 for invalid key AND non-existent forms) |
| Anti-Bot | Cloudflare Turnstile validation | Required on all submissions; 502 if Turnstile API unreachable |
| Rate Limiting | Per-form + global limits | Redis-based, fail-closed, configurable limits, Retry-After header |
| Origin Validation | Per-form allow-list | 403 Forbidden for disallowed origins |
| Payload Limits | Request body size enforcement | 2MB default, configurable via MAX_PAYLOAD_SIZE_BYTES |
| Data Sanitization | XSS prevention | HTML entity escaping, Unicode NFKC normalization, string truncation |
| Schema Validation | JSON Schema (Draft 2020-12) | Runs before sanitization; format validation included |
| Secret Masking | Credentials never logged | API keys, connection strings masked in log output |
Transport Security
All communication with the Formic API is encrypted in transit:
- Client → API: HTTPS terminated at the Caddy reverse proxy layer
- API → Database: TLS for PostgreSQL connections
- API → Email: TLS for SMTP (Lettre with
tokio1-rustls-tls) - API → Cloudflare: HTTPS for Turnstile verification
Related
- Authentication — API key management and best practices
- Anti-Abuse Protections — Rate limiting, Turnstile, origin validation
- Data Protection — Sanitization, encryption, metadata