FormBridge implements security best practices throughout its codebase. This document outlines the security measures in place.
- Storage: API keys are SHA-256 hashed at rest — raw keys are never stored
- Scoping: Keys can be scoped per intake and operation (read/write/approve/admin)
- Expiration: Optional expiration dates for time-limited access
- Format:
fb_key_<uuid>prefix for easy identification
- Roles:
admin,reviewer,viewer - Permissions: Granular permission matrix (intake:read, submission:write, approval:approve, etc.)
- Enforcement: Permission checks on every protected route via middleware
- Signature Verification: Full cryptographic verification via JWKS (JSON Web Key Sets)
- Algorithm Restrictions: Only asymmetric algorithms allowed by default (RS256, ES256, PS256, etc.)
- Security: 'none' algorithm explicitly rejected; HS256 requires explicit opt-in
- Claims Validation: Issuer, audience, and expiration strictly enforced
- Key Rotation: Automatic JWKS refresh with caching for performance
- Tenant isolation via configurable claims
- All API inputs validated with strict type checking
- Body size limits (1MB default) via middleware
- Reserved field names blocked (
__proto__,constructor,prototype) to prevent prototype pollution
- UUIDv4-based (cryptographically random via
crypto.randomUUID()) - Rotated on every state change
- Required for all submission modifications
Webhook destinations are validated to prevent Server-Side Request Forgery:
- Private IPs: RFC 1918 ranges (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
- Loopback: 127.0.0.0/8, localhost
- Link-local: 169.254.x.x (includes AWS IMDS at 169.254.169.254)
- IPv6: ::1, fe80::/10, fc00::/7, IPv4-mapped addresses
- Schemes: Only
http:andhttps:allowed
- URL validation occurs at both enqueue time AND delivery time
- Prevents attacks where DNS resolves to internal IP after initial validation
- Destination headers are sanitized
- Blocked headers: Host, Content-Type, Content-Length, X-FormBridge-Signature
- Signing: HMAC-SHA256 signatures on all webhook payloads
- Verification: Constant-time comparison via
timingSafeEqual(prevents timing attacks) - Headers:
X-FormBridge-SignatureandX-FormBridge-Timestampincluded - Retries: Exponential backoff with configurable retry policy
- Parameterized Queries: All database operations use prepared statements
- No String Concatenation: User input is never interpolated into SQL
- Type Guards: Runtime validation of all data retrieved from storage
- Configurable: Not wide-open by default
- Production Preset: Requires explicit allowed origins
- Dev Preset: Permissive but clearly marked as development-only
- Credentials: Proper handling with origin validation
Applied via Hono's secureHeaders() middleware:
Content-Security-PolicyX-Frame-Options: DENYX-Content-Type-Options: nosniffStrict-Transport-Security(HSTS)Referrer-Policy
- Production Mode: Error messages sanitized, no stack traces leaked
- Development Mode: Detailed errors for debugging (opt-in)
- Consistent Format: All errors follow IntakeError schema
- Presigned URLs: Files upload directly to S3 — server never handles raw bytes
- Constraints: Size limits, MIME type validation, file count limits
- Expiration: Upload URLs are time-limited
- Isolation: Uploaded content served from separate domain/bucket
- Per-Tenant: Rate limits applied per tenant/API key
- Configurable: Adjustable limits and windows
- Headers: Standard rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset)
- Dedicated security tests in
tests/security/ - URL validation tests covering SSRF bypass techniques
- Header sanitization tests
- Idempotency Keys: Uses database unique constraints. For high-concurrency multi-instance deployments, consider distributed locking if exact-once semantics are critical.
- Rate Limiting: In-memory rate limiter is per-instance. For multi-instance deployments, use Redis-backed rate limiting.
- Files are uploaded directly to S3 via presigned URLs — the server never handles raw bytes
- MIME type validation relies on client-provided type + S3 constraints
- For applications that process uploaded files server-side (not FormBridge's default pattern), implement magic byte validation
If you discover a security vulnerability, please report it responsibly:
- Do not open a public GitHub issue
- Email security concerns to the maintainers
- Allow reasonable time for a fix before public disclosure
Last audited: 2026-02-03 (VibeSec)