Security Overview
Simcha DB Studio executes SQL and DDL against production databases and custodies live credentials for every managed connection. The threat model is accordingly a privileged one: the application is both an authenticated multi-user surface and a secret store. Controls are layered so that a failure in any single control does not collapse the whole posture.
Control Layers
| Layer | Mechanism | Property enforced |
|---|---|---|
| Authentication | Stateless JWT (HS256), bcrypt(12) credential hashing, optional TOTP MFA | Identity assurance; no server-side session store to compromise or exhaust |
| Authorization | RBAC middleware (extractUser / requireAuth / requireRole) over 5 roles; license-tier route gating | Least privilege; separation of duties across the change-management workflow |
| Secret confidentiality | AES-256-GCM at rest with per-record PBKDF2-SHA512 key derivation | Connection passwords, MFA secrets, and sensitive settings unreadable at rest |
| Transport / header hardening | Helmet-managed headers incl. HSTS and CSP; strict CORS allowlist | Downgrade, framing, MIME-sniff, and cross-origin abuse mitigated |
| Abuse control | Tiered rate limiting (general vs. DB DevOps bulk windows) | Credential stuffing, brute force, and API flooding throttled |
| Accountability | Global audit middleware writing a DB-sealed, append-only hash chain | Non-repudiable, tamper-evident record of every state change |
Trust Boundaries
The browser never speaks to Express directly. Requests traverse Next.js API routes (pages/api/*) which forward to the Express backend, propagating Authorization, X-Request-Id, and the non-prod X-QA-Bypass-Key header. Auth, RBAC, license gating, encryption, and audit all execute server-side; the frontend holds a bearer token and nothing else of consequence. The bypass headers (X-QA-Bypass-Key, X-Agent-Key) that inject a virtual admin are hard-gated to NODE_ENV !== 'production', leaving them enabled in production is a critical finding.
HTTP Header Posture (Helmet)
| Header | Value | Rationale |
|---|---|---|
Strict-Transport-Security | max-age=31536000 | Pins HTTPS once seen over TLS; forecloses SSL-strip on repeat visits |
Content-Security-Policy | self + 'unsafe-eval' | unsafe-eval is required by the Monaco editor's AMD loader; the remainder of the policy constrains script/style origins to defeat inline injection |
X-Frame-Options | SAMEORIGIN | Clickjacking / UI-redress defense |
X-Content-Type-Options | nosniff | Blocks MIME confusion on responses |
X-DNS-Prefetch-Control | off | Suppresses side-channel DNS leakage of embedded origins |
CSP intentionally retains unsafe-eval. This is a known, scoped exception for Monaco, not blanket permissiveness, treat any additional CSP relaxation as a reviewable change.
Secrets Handled by the Application
- User credentials, bcrypt(12), unique per-hash salt, timing-safe verification. Never logged or echoed after the auth request.
- Managed connection passwords, AES-256-GCM at rest (
enc:wire format below); decrypted only at pool-open time viaExecutionRepository/ConnectionRepository.findByIdRaw(); masked in ordinary reads. - Repository / cloud tokens, GitHub, GitLab, Bitbucket, S3, Azure Blob, Dropbox credentials encrypted at rest in
repo_connections; decrypted only for the outbound API call. - MFA secrets and backup codes, TOTP seed encrypted at rest; backup codes stored as SHA-256 hashes, never plaintext.
- License signing key, server-side only; never serialized into API responses or the client bundle.
Deployment Prerequisites (fail-loud, not fail-open)
| Control | Severity | Requirement |
|---|---|---|
JWT_SECRET | Critical | ≥64 chars of CSPRNG output, from a secrets manager. Compromise = universal token forgery across all roles. |
ENCRYPTION_KEY | Critical | High-entropy; required. If unset, EncryptionService no-ops and stores connection passwords and MFA seeds in plaintext (warn-logged only). Never deploy without it. |
| TLS termination | Critical | TLS 1.2+ at the edge; HTTP→HTTPS redirect. HSTS is emitted by Helmet once served over TLS. |
| Datastore isolation | Critical | The changeops/DevOps Postgres in a private subnet; ingress only from the app. |
| Non-prod bypass headers off | Critical | Confirm NODE_ENV=production so X-QA-Bypass-Key / X-Agent-Key are inert. |
| Managed-DB TLS | High | sslmode=require or verify-full to target databases. |
| Secret rotation | High | JWT_SECRET annually / on suspicion; DB passwords quarterly; repo tokens per provider policy. |
| Image scanning | High | Block critical/high CVEs pre-deploy; pin immutable tags. |