Features → Security
Security model designed for MSPs handling other companies' data
Per-tenant MySQL database isolation. AES-256-GCM encryption at rest. TOTP MFA + SAML SSO. 300+ granular permissions. Admin IP allowlist. ClamAV on uploads. Infisical secrets vault. Triple-codebase quarterly security audits. The defenses an MSP needs when they're the ones answering for their own customers' data.
Controls
Every item below is live in production. Where a control is plan-gated or opt-in, that's called out on the relevant feature or pricing page.
Per-Tenant MySQL Database
Each customer's data lives in a dedicated MySQL database (saas_tenant_<slug>). Not a shared schema with row-level tenant_id filters. Not multi-tenant rows you have to remember to scope. Cross-tenant queries are not possible by design — the database connection is bound to one tenant per session, period.
AES-256-GCM Encryption at Rest
PII fields (phone, address, last_four), integration tokens (OAuth refresh tokens, API keys, webhook secrets, SAML certs), and MFA secrets are encrypted with authenticated AES-256-GCM. Encryption key managed via environment variable or Infisical vault; can be rotated on-demand with a 30-day rollback window.
TLS 1.3 in Transit
All connections — web, API, customer portal, back-end — terminate TLS 1.3 with modern ciphers only. No legacy fallbacks. HSTS enabled.
Two-Factor Authentication (TOTP)
TOTP MFA available for both staff and customer-portal users. Compatible with Google Authenticator, 1Password, Authy, Microsoft Authenticator, etc. Recovery codes issued at setup. MFA secrets stored encrypted.
SAML SSO
SAML 2.0 single sign-on against Entra ID, Google Workspace, Okta, or any compliant IdP. SP-initiated and IdP-initiated. SAML logins skip TOTP by design — the IdP IS the second factor. Allowed-domains gate prevents cross-IdP user provisioning.
Role-Based Access Control (300+ Permissions)
Fine-grained permissions on 98 modules across the platform. Pre-built roles for staff, billing, sales, dispatch, and read-only — or define your own. Every API route enforces required permissions; UI is just a hint.
Admin IP Allowlist
Restrict admin-area access to specific IPs or CIDR ranges. Session cookies carried off-LAN no longer authorize destructive operations. Per-action checks (not just initial login) — a stolen cookie used from a non-allowlisted IP gets a 403, not a usable session.
Account Lockout
Per-account brute-force protection: failed_login_count + locked_until columns. 5 wrong passwords lock the account for 30 min. DB-backed so it survives PM2 restart and a distributed brute force can't reset the counter by hitting different app servers.
ClamAV Malware Scanning
Every file upload — staff and portal — runs through ClamAV before it's accepted. Fails closed if the daemon is unavailable. Layered with magic-byte type detection and an extension allowlist that blocks 50+ executable file types.
Storage Quota + Upload Hardening
Per-plan storage quotas enforced at upload time. MIME claim validated against actual magic bytes. Archive contents (zip) inspected — embedded executables rejected even though the wrapper itself is allowed.
Comprehensive Audit Logging
Every state-changing action is logged with user + IP + timestamp + entity. Audit log is decrypt-on-read (encrypted at rest, same encryption envelope as PII). Visible to the customer on every relevant entity (customer, ticket, invoice, project, KB article) plus a tenant-wide /reporting/audit view.
Session Management
DB-backed sessions with sliding-window idle timeout (30 min idle = kicked, 8 hr absolute max). Cookie attributes: HttpOnly, Secure, SameSite=Lax. Session fixation prevented via session-ID rotation after MFA verify. CSRF middleware enforces Origin + Referer headers on every state-changing method.
Secrets Vault (Infisical)
Production secrets managed via self-hosted Infisical (HA pair on the infraadmin host). App servers fetch secrets at boot via machine-identity OIDC; no plaintext secrets on disk. Per-environment + per-service secret paths. Rotation tracked in secret_rotation_history.
Encryption Key Rotation
On-demand AES-256-GCM key rotation across all tenant databases. Rolling rollout per app server (drain → rotate → re-encrypt → restart). Old keys retained for 30 days for rollback. Audit-logged with start + complete timestamps.
QuickBooks Drift Detection
Edits made inside QuickBooks after sync are flagged on the next round-trip. Banner appears on the invoice/estimate with the diff — you decide which side is the source of truth, rather than discovering the discrepancy at audit time.
Webhook Authenticity
Outbound webhooks HMAC-SHA256 signed with a per-subscription secret so receivers can verify. Inbound webhooks (Stripe, QBO, signature providers, telephony) validate provider signatures via timingSafeEqual — replay attacks blocked by timestamp + nonce where the provider supports it.
Compliance posture
- GDPR-aligned (data subject rights tooling, DPA available)
- CCPA-aligned (consumer rights tooling)
- Stripe SAQ-A scope — your team never sees raw card data
- Per-customer data export available on request
- Sub-processor list published at /legal/subprocessors
- Multi-tenant SaaS — your DB is yours, not a shared row pool
SOC 2 / ISO 27001 attestations: not in scope today. We document the controls equivalent to those frameworks transparently here; formal attestations are on the roadmap for the larger customer tier.
What we verify
- Customer-tenant data does NOT leak across tenants — verified by triple-codebase security audits (2026-05-10, 2026-05-13, 2026-05-16) covering OWASP Top 10 surfaces.
- Encryption keys are NEVER stored in the same database as the encrypted data.
- We do NOT store customer-of-customer credentials. If a tenant needs to track a customer's password for a service, OriginPSA refers them to an external password manager — by policy.
- Telnet and SSH router credentials are encrypted; password-auth routers warn before use; SSH key auth is the recommended path.
Need our DPA or sub-processor list?
Data Processing Addendum at /legal/dpa. Sub-processors list at /legal/subprocessors. SLA at /legal/sla. Counter-signed copies available on request via /contact.