Skip to content
SECURITY

How we protect your data

Last updated: July 25, 2026

Security is not a feature we add later — it is built into the architecture from day one.

Authentication

Powered by Supabase Auth (Supabase holds SOC 2 Type II certification — this is their certification, not Ruunly's). Passwords are hashed with bcrypt — we never store plaintext passwords. Business owners log in with email + password. End customers use magic links by default, eliminating password attack surface.

Database Isolation

Operational data — customers, invoices, payments, jobs, messages — is isolated at the database level with PostgreSQL Row-Level Security (RLS). For those tables, even if someone bypassed our application layer, the database itself enforces that Tenant A can never see Tenant B's data. A small set of website content tables (pages, blog posts, media) is managed by our CMS and separated by application-level tenant filtering rather than RLS. RLS policies are covered by automated pgTAP tests that run in CI on every change.

Payments

Payment processing is handled by Stripe (PCI DSS Level 1). Ruunly uses Stripe-hosted Checkout for subscription and payment-method collection. Card data never touches Ruunly servers, and we do not store card numbers at all — the card brand and last 4 digits shown in your dashboard are read from Stripe when the page loads.

File Storage

All uploaded files are stored in Cloudflare R2. Buckets are never public — files are only accessible via time-limited presigned URLs (15 minutes for uploads, 1 hour for downloads). Files that pass through our servers — business logos, customer-submitted job photos, booking and intake-form attachments, and AI proposal audio and photos — are validated by magic bytes, so a file that is not really the image type it claims to be is rejected. Uploads that go straight from the browser to storage — the photo gallery, expense receipts, and job photos posted from the dashboard or mobile app — are limited to an allowlist of image types and a maximum size, and we verify what actually landed in storage before recording it.

Encryption

  • All data in transit: TLS 1.3 via Cloudflare
  • All data at rest: AES-256 encryption on the database storage volume
  • Sensitive integration credentials (bank and accounting tokens) additionally encrypted at the application layer with AES-256-GCM
  • Database runs on an isolated private host, not exposed to the public internet
  • JWT access tokens expire after 15 minutes
  • Sensitive configuration (API keys, secrets) stored in environment variables, never in code

Shared Responsibility

Security is shared between Ruunly and each business customer. Ruunly is responsible for securing the platform infrastructure, application controls, tenant isolation, and integrations we operate. Business customers are responsible for using strong passwords, limiting staff access, protecting their devices, reviewing team permissions, configuring Stripe and messaging features lawfully, and promptly notifying Ruunly of suspected account compromise.

Compliance Posture

Ruunly uses service providers with security certifications, including Stripe for PCI DSS Level 1 payment processing, Supabase for hosted authentication, and Hetzner (ISO 27001 data centers) and Cloudflare for infrastructure. These are provider certifications and do not mean Ruunly itself is certified under those frameworks.

Ruunly designs its privacy and security program to support CCPA and other U.S. privacy law obligations. CCPA is not a certification program. Our data processing terms and the current subprocessor list are published, not request-only — see the Data Processing Addendum and Subprocessors.

Incident Response

Ruunly maintains procedures to triage, investigate, contain, and remediate suspected security incidents. If Ruunly determines that a security incident requires notice under applicable law or contract, Ruunly will notify affected customers without undue delay and provide information reasonably available at the time, including the nature of the incident, affected data categories, mitigation steps, and customer actions where applicable.

Access Controls and Auditability

Ruunly restricts production access to authorized personnel and service accounts with a business need. Administrative actions are logged with user, tenant, timestamp, and action metadata, including payment configuration changes, which are auditable. Payout and identity details for a connected payment account are collected and changed on Stripe's own hosted onboarding pages, under Stripe's authentication and identity verification, rather than inside Ruunly.

Vulnerability Disclosure

Ruunly welcomes responsible vulnerability reports. Researchers must act in good faith, avoid privacy violations, avoid service disruption, avoid data destruction or exfiltration, and give Ruunly reasonable time to investigate before public disclosure. Ruunly will not pursue legal action for good-faith research that follows these rules.

Email: [email protected]