Skip to main content
Security at OEC.sh

Security at OEC.sh

We're a deployment platform, not a hosting provider. Your servers stay under your cloud account. Here's how we protect everything else.

Per-org isolation
Strict tenancy
Audit logs
Up to 1 year
5-layer SSRF defense
URL inputs
Zero-trust tokens
Short-lived, signed
15 min read
Updated May 2026

What OEC.sh Actually Is

Before we get into specifics, the framing matters. OEC.sh is a tool that manages Odoo on your servers, in your cloud account. We don't host your databases. You do, on AWS, Hetzner, DigitalOcean, GCP, Azure, OVH, Vultr, Linode, Alibaba, or wherever you choose to run.

That split is important for any threat model. It means a compromise of OEC.sh does not give an attacker direct access to your Odoo databases or customer data, because that data never sits in our infrastructure. Our control plane holds deployment metadata, audit trails, encrypted tunnel credentials, and the API keys you create. Your Odoo runtime lives somewhere else entirely.

Our responsibility is the control plane: dashboards, the public API, deploy logic, role-based access control, audit logging, the browser SSH terminal, webhook delivery, and the Cloudflare-backed routing layer for SaaS domains.

Your responsibility is cloud security on your provider account, server hardening, backup retention policies, the user accounts inside your Odoo instance, and the data you put into it. We give you the controls to manage all of that. We don't reach across the line into your cloud account on our own.

Authentication and Access

Getting into your OEC.sh account should be hard for attackers and easy for you. We support the modern primitives so you can pick what fits your team.

Two-factor and passkeys

Every account can enable 2FA using a TOTP authenticator (1Password, Authy, Google Authenticator), or use WebAuthn passkeys for phishing-resistant login. Passkeys work with platform authenticators (Touch ID, Windows Hello) and roaming authenticators (YubiKey).

SSO via OAuth

Sign in with Google, GitHub, GitLab, or Bitbucket. The OAuth flow means your credentials never touch our servers. If your team uses Google Workspace, you can enforce SSO at the identity provider level.

Session management

Sessions use secure, HTTP-only cookies with the SameSite flag set. Inactive sessions time out automatically. You can view active sessions and revoke any of them from your account settings.

SSH key management

SSH keys are scoped per server, not per account. You can rotate them or revoke them at any time. Private keys never leave your machine, because we only store the public half.

Browser SSH terminal

The in-dashboard SSH terminal uses signed, short-lived tokens. Sessions are minted server-side, expire quickly, and there are no long-lived secrets sitting in the browser. The terminal connects through our backend, which means traffic to your server uses the SSH key you authorized for that connection.

Role-Based Access Control

Most security incidents start with someone having more access than they need. RBAC on OEC.sh is built around the principle of least privilege.

Granular permissions

Pro orgs get 55+ distinct permissions covering deployments, environments, servers, registration tokens, webhooks, and team management. You can grant a contractor the ability to deploy without letting them edit billing or invite new members.

Custom roles

Agency orgs can define custom roles by combining permissions. Create a "Read-only auditor" role for compliance reviewers, or a "Deployment engineer" role for ops staff who shouldn't see billing. Roles can be assigned per org membership.

Per-org membership and ownership

A user can belong to multiple orgs, each with a different role. Ownership is a separate flag from membership. Only owners can transfer ownership, delete the org, or change billing. Permissions enforced on every API call, not just in the UI.

Cross-org Connect-As (Agency)

Agencies often need to operate on a client's account. Connect-As makes this auditable and revocable. The client org must explicitly grant Connect-As permission. When the agency redeems it, we mint a cryptographically signed token, time-bound to a short session window.

Every Connect-As session is logged on both ends. The source org sees who connected to which client and when. The target org sees that an agency user acted on their behalf, with the original user's identity preserved in the audit trail. There is no "ghost" mode.

Read more in our Connect-As documentation.

Audit Logs

You can't investigate what you can't see. Audit logs are tied to plan tier:

PlanAudit LogsRetentionExport
FreeNot availableN/AN/A
Starter ($19/mo)Not availableN/AN/A
Pro ($39/mo)Full action history30 daysUI only
Agency ($199/mo)Full action history1 yearExportable (CSV, JSON)

Logged actions include deployments, environment start, stop, and restart events, server connections, Connect-As sessions on both ends, registration token use, API key creation and revocation, role changes, and member invites and removals.

Audit logs are tamper-evident. They're visible to org owners and administrators, and they cannot be edited or deleted by org members, including owners. If a member is removed, their actions stay in the log under their original identity.

Data Security

Your Odoo database contents never enter our control plane. Here's what we do with the data we do handle.

Per-org isolation

Every record in our control plane is scoped to an org. Queries are filtered at the data-access layer, not just at the UI. There is no shared cache across orgs. Audit trails, registration tokens, API keys, webhook destinations, custom domains, and Mailtest captures are all per-org.

Encryption at rest

Our database storage is encrypted at rest by the underlying cloud provider. On top of that, we run our own keystore for sensitive values that need application-level encryption: tunnel credentials, OAuth refresh tokens, and the API keys we generate. These values are encrypted before they reach the database.

Encryption in transit

TLS everywhere. The dashboard, API, browser SSH terminal, and webhook delivery all use TLS 1.2 or higher. For SaaS domains we route through Cloudflare for SaaS, which terminates TLS at the edge and auto-provisions SSL certificates for your custom domains.

Database backups

Backups go to your own S3, Cloudflare R2, or Backblaze B2 bucket under your account. We never copy your database backups to our infrastructure. You configure the bucket once, set the retention policy you want, and own the data outright. If you cancel OEC.sh tomorrow, your backups are still in your bucket.

Mailtest captures

Mailtest captures outbound email from your Odoo dev or staging environment for inspection. Captures are isolated per org, never shared, and auto-deleted according to the retention policy you set. You can purge captures manually at any time.

What we don't see

We never see the contents of your Odoo database in our control plane. Customer records, invoices, employees, and the rest of your business data live on your server. The dashboard talks to your server over an authenticated channel for operational actions, but it doesn't ship your data back to us.

Network Security

The network path between your users, your Odoo, and our control plane is where a lot of security goes wrong. Here's the setup.

Cloudflare for SaaS at the edge

Custom domains route through Cloudflare for SaaS. That means TLS is terminated at the edge, DDoS protection is included by default, and certificate provisioning happens automatically. Your customers connect to a global anycast network rather than a single origin server.

Cloudflare Tunnel for private servers

For private Odoo servers (BYOS, bring-your-own-server), we support Cloudflare Tunnel as the connection mechanism. No inbound ports need to be open on your server. The tunnel agent makes an outbound connection to Cloudflare, and OEC.sh routes traffic to your Odoo through that tunnel. Your firewall can stay locked down.

Per-org service tokens

Tunnel access uses per-org service tokens, not shared credentials. Rotating or revoking a token affects only the org that owns it. Tokens are stored in our keystore in encrypted form.

Custom domain isolation

Each org's custom domains are scoped to that org. You cannot claim a domain that belongs to another org, and a domain's routing rules only apply to deployments under the same org. The verification flow uses DNS or HTTP file challenges, so you have to prove ownership before traffic is routed.

Application-Layer Hardening

The infrastructure is one half of the story. The other half is what happens inside the application code itself.

5-layer SSRF defense

Anywhere our backend fetches a user-supplied URL (migration imports, webhook destinations, HTML preview in Mailtest), the URL passes through five layers of checks: scheme allow-listing (https only), DNS resolution with private-IP rejection, redirect following with re-validation at each hop, request size limits, and a separate egress proxy that enforces the rules at the network layer. A malicious URL that points at 169.254.169.254 or an internal RFC1918 address gets blocked at multiple points.

Trusted download domain allow-list

Regulated customers can lock URL inputs to an explicit allow-list per org. Once enabled, only the domains you approve can be used as sources for migrations and imports. Useful when you want to be sure no contractor can introduce code from a random domain.

Rate limiting

The public API is rate-limited per API key, with separate buckets for read and write operations. Authentication endpoints have stricter limits with progressive backoff to slow down credential-stuffing attacks. You won't notice the limits during normal use, but they kick in if something automated starts hammering an endpoint.

Webhook signature verification

Every webhook we deliver is signed with HMAC-SHA256, using a secret unique to your webhook destination. Your receiver verifies the signature before processing the payload. Signature secrets can be rotated without downtime by holding both keys valid during a grace window.

Clone-disable kill-switch

Org owners can disable environment cloning entirely. For regulated customers worried about a developer accidentally copying production data into a less-controlled environment, this is a single toggle. When clone is disabled, the option simply isn't available in the UI or the API for that org.

Pre-flight deploy checks

Before a deploy executes, we run pre-flight checks that validate SSH access to the target server, port reachability, firewall configuration, available disk space, and the integrity of the previous deploy. Failed checks abort the deploy with a clear error rather than leaving the server in a half-changed state.

What We Don't Claim

Plenty of vendors list certifications they don't actually hold, or hide the scope. We'd rather be direct.

  • No SOC 2 Type II certification. We follow many of the same controls, but we have not been through the audit.
  • No ISO 27001 certification. Same story.
  • No HIPAA Business Associate Agreement. If you handle protected health information, your Odoo deployment and your cloud provider need the appropriate controls, but we are not in that contractual chain.
  • No PCI DSS compliance. If you process cardholder data inside Odoo, you handle PCI scope on your own instance. We don't see card data.

We follow industry best practices and we've built the platform with these frameworks in mind, but we haven't paid for the audits yet. If you need certifications today, the underlying cloud providers (AWS, GCP, Azure) have them, and your Odoo deployment running on those providers inherits the infrastructure-level controls. If you'd like to talk about a roadmap for our own audits, get in touch.

What You Control

A platform is only as secure as the controls in the customer's hands. Here's what stays with you.

  • Your cloud account. We don't have access to it. You give your OEC.sh server an SSH key when you onboard, and that's the extent of our reach.
  • Your server access. SSH keys are yours. Rotate them whenever you want.
  • Your data residency. Pick the cloud region. Frankfurt, Sydney, São Paulo, anywhere your provider operates.
  • Your backup retention. Configure how often and how long, per environment.
  • Your team access. RBAC, custom roles on Agency, and the Connect-As toggle are all in your hands.
  • Registration tokens. Scoped and revocable. A token compromised six months ago can be revoked today without disrupting anyone else.

If you want a deeper conversation about how to set this up for a regulated environment, our enterprise page covers the contract and SLA side, and the contact form goes straight to our team.

Vulnerability Disclosure

Found a security issue? We want to hear about it. Send details to security@oec.sh or reach us through the contact form.

Our response target is 48 hours for valid reports. We'll acknowledge receipt, confirm reproduction, and keep you updated as we work on a fix. For critical issues we move faster.

We don't run a formal bug bounty program yet. We do acknowledge contributors publicly (with your permission), and we're happy to send swag and credit for any reproducible report.

Please don't run automated scanners or pen-testing tools against production without contacting us first. Coordinated disclosure beats surprise traffic.

Frequently Asked Questions

Do you hold SOC 2 or ISO certifications?

No. We do not currently hold SOC 2 Type II, ISO 27001, HIPAA, or PCI DSS certifications. We follow industry best practices, but we have not paid for the formal audits yet. If you need certifications today, the underlying cloud providers (AWS, GCP, Azure) hold them, and your Odoo deployment running on those providers inherits the infrastructure-level controls.

Where is my data stored?

Your Odoo databases live on the servers you provision in your own cloud account (AWS, Hetzner, DigitalOcean, GCP, Azure, OVH, Vultr, Linode, Alibaba, and so on). Database backups are stored in your S3, R2, or B2 bucket under your account. OEC.sh stores only the metadata required to manage your deployments: configuration, audit logs, encrypted tunnel credentials, and API keys.

Who has access to my Odoo database?

The team members you invite to your org and grant the appropriate role. OEC.sh staff do not access your Odoo database contents. We can access deployment metadata (configuration, logs, audit trail) when required for support, and only after you raise a ticket. Your database credentials are stored on your server, not in our control plane.

What happens if OEC.sh goes down?

Your Odoo instance keeps running. Because OEC.sh is a control plane, not a runtime, your customers continue using your Odoo even if our dashboard is unavailable. You temporarily lose the ability to deploy, rollback, or use the dashboard until we recover. Your data stays with you.

Can I disable Connect-As entirely?

Yes. Org owners on Agency can toggle Connect-As off for the entire org, and revoke any active session at any time. Pro orgs can also restrict Connect-As at the membership level. For regulated customers, we recommend enabling the Clone-disable kill-switch as well to prevent environment cloning entirely.

Ready to Talk Security?

Try the free plan and stress-test the controls yourself, or book time with our team to review your specific requirements.