Skip to main content

SalesOS Trust Center

How the SalesOS CRM protects your data today, stated plainly, including the parts that are not finished yet.

At a glance

  • Hosted in one region: Oracle Cloud Infrastructure, Mumbai, India.
  • HTTPS only, with TLS 1.2 or 1.3. Older TLS versions are refused.
  • Passwords hashed with bcrypt; stored integration credentials encrypted with AES-256.
  • SSO with SAML 2.0 or OpenID Connect, and SCIM 2.0 provisioning.
  • Every request is checked against your organization membership.
  • No SOC 2 or ISO 27001 certification yet; see the roadmap.

Architecture and hosting

SalesOS runs on Oracle Cloud Infrastructure (OCI) in the Mumbai region (ap-mumbai-1), India. The web app is served as static files by nginx, the API is a NestJS service, and the PostgreSQL 12 database runs on the same host and accepts connections only from that host.

Cloudflare sits in front of salesos.org for DNS and proxying. Browsers connect to Cloudflare, and Cloudflare connects to our server over TLS using a Cloudflare origin certificate.

Data residency

Customer data is stored in India. There is one region and no choice of region today. Some sub-processors, such as email delivery and the AI gateway, handle data outside India; the sub-processor list says which.

Encryption

In transit

  • Plain HTTP requests are redirected to HTTPS.
  • Only TLS 1.2 and TLS 1.3 are accepted, both at Cloudflare and at our server.
  • API responses send Strict-Transport-Security (one year, including subdomains) and a Content Security Policy.

At rest

  • Passwords are hashed with bcrypt (cost factor 10). We never store them in readable form.
  • Stored secrets are encrypted in the application with AES-256 before they reach the database: integration credentials, OAuth app credentials and payment gateway settings use AES-256-GCM; SSO client secrets, LLM provider keys, two-factor secrets and Salesforce tokens use AES-256-CBC. The key is held on the server, not in the database.
  • Two-factor backup codes, SCIM tokens and API keys are stored as hashes.
  • OCI encrypts its block and boot volumes at rest by default with Oracle-managed keys. We do not add separate operating-system disk encryption.
Not in place yet: OAuth tokens for connected Gmail, Outlook and calendar accounts are not yet encrypted at the field level (no such connections exist in production today), and database backups are not encrypted. Both are on the roadmap. Security headers such as HSTS are not yet sent on the marketing web pages, only on the API.

Sign-in and sessions

  • Passwords must be 12 to 128 characters with an uppercase letter, a lowercase letter, a number and a symbol.
  • After 10 failed sign-in attempts the account is locked for 15 minutes.
  • Access tokens last one hour and are renewed while you keep working. You can sign out a single session or all your other sessions under Settings → Security, and resetting your password ends every session.
  • Two-factor authentication with an authenticator app (TOTP), plus 10 single-use backup codes. Platform administrators can require it for all users, for admins or for managers, with a grace period to enrol.
  • Single sign-on per organization with SAML 2.0 (signed assertions required) or OpenID Connect (authorization code flow with PKCE). An organization can require SSO for its email domain, which turns off password sign-in for those users.
  • SCIM 2.0 provisioning for users and groups. Tokens are scoped to one organization, and deprovisioned users are deactivated, not deleted.
  • API keys are stored as hashes and can be scoped per resource, given an expiry date and limited to listed IP addresses.
  • State-changing requests from the web app need a CSRF token tied to the session.
Rate limits
Applies toLimit
Every API route, per IP address20 requests a second, 200 a minute, 2,000 an hour
Sign-in, registration and code verification10 a minute
Password reset and other account-lookup requests3 every 5 minutes
Not in place yet: Sign-in asks for a two-factor code only when the enforcement policy covers that user's role, so a user who turned on 2FA but is not covered by the policy is not asked for a code. There is also no idle timeout or fixed maximum session length yet. Fixing both is on the roadmap.

Tenant isolation

Every organization's records carry its organization id. Each signed-in API request passes an organization guard that confirms you are an active member of the organization you are acting in and that the organization is active, and the services filter their database queries by that organization. Screens that read across organizations are limited to SalesOS platform administrators.

PostgreSQL row-level security policies are defined on 22 core tables, including leads, contacts, accounts, deals, quotes, orders, tasks and notes.

Not in place yet: The database role the application uses currently bypasses those row-level security policies, so isolation today depends on the application checks above rather than on the database. Enforcing the policies for the application is on the roadmap.

Access control

  • Two kinds of role: a platform role (Admin, Manager, User, Viewer) and a role in your organization (Owner, Admin, Manager, Member).
  • Profiles set per-module permissions (read, create, edit, delete) and record visibility (none, own, team or all) for the users they are assigned to.
  • Field-level security hides or locks individual fields on leads, contacts, accounts, deals, tasks and cases, both in responses and on save.
  • Record sharing grants a user or a team read or edit access to one record, optionally until a set date.
  • Bulk ownership transfer is always confined to your own organization, is capped per request, and can be previewed before it runs.

Audit trails

  • Administrative actions (user and role changes, configuration changes, impersonation, bulk transfers, DPA acceptance) are written to an admin audit log.
  • Field-level change history is recorded automatically for accounts, deals, contracts, quotes, orders, leads and contacts, showing who changed what and when.
  • Successful and failed sign-ins are logged.

Backups

We take full PostgreSQL backups with pg_dump. The backup script keeps the seven most recent, and a restore can be run from any of them.

Not in place yet: Backups are taken by an operator rather than on an automatic schedule, they are stored on the same server as the database, they are not encrypted, and there is no off-site copy. Scheduled, encrypted, off-site backups with regular restore tests are on the roadmap.

Monitoring and status

The status page checks the API, the database, background jobs, AI availability and email delivery live, every time it loads, and shows any service notice we post.

Not in place yet: The status page shows the current state only, with no incident history. There is no external uptime monitor, and error-tracking reporting is not switched on.

Report a vulnerability

Email [email protected] with the steps to reproduce the issue and how to reach you. Our contact details are also published in security.txt.

  • Test only against your own account and organization. Do not access, change or delete other customers’ data.
  • Do not run denial-of-service tests, spam or social engineering against our staff or customers.
  • Give us a reasonable amount of time to fix the issue before you share it publicly.
  • We do not run a paid bug bounty.

Incident response

If you think your account or data has been compromised, email [email protected]. Settings → Security lets you sign out every other session straight away, and a password reset ends them all.

Not in place yet: A written incident response procedure has been drafted and is not yet adopted. Our commitments on notifying customers about a personal data breach will be set out in the Data Processing Agreement once it is published.

Last reviewed 29 September 2026. Questions about anything here: [email protected].