Security

Fail-closed at every layer. Open about every layer.

Engine: 15 of 15 external audit findings closed. App surface: SOC 2 via Assembly. Infrastructure: Microsoft Azure. Most trust portals gate the details. Ours doesn't.

Posture at a glance
Engine · Ditto
15 / 15
External audit findings closed (April 2026, across 6 PRs).
App surface · Assembly
SOC 2
Continuous control monitoring via Secureframe. GDPR, CCPA, HIPAA aligned.
Infrastructure · Microsoft Azure
ISO 27001
Plus SOC 1 / SOC 2 / SOC 3, HIPAA, FedRAMP High, and 90+ inherited certifications.

Where your data lives

Three layers. Each audited on its own terms.

Customer data passes through Ditto's rendering engine, surfaces in the Assembly app for client review and approval, and rests on Microsoft Azure infrastructure. Each layer carries its own attestations and its own controls. We don't outsource any layer's posture to the layer below.

Layer 1 · Engine

Ditto

HMAC webhook verify SSRF guard Path-traversal block Per-client API keys PII redaction Zod input validation CSP nonce
15 / 15 External audit · April 2026
Layer 2 · App surface

Assembly ↗

SOC 2 Secureframe monitored GDPR · CCPA · HIPAA aligned MFA enforcement Encryption at rest + transit JML policy IR tabletops
SOC 2 Continuous · Secureframe
Layer 3 · Infrastructure

Microsoft Azure ↗

Container Apps Customer-managed keys Front Door TLS Deny-all egress Two-domain isolation Encrypted blob storage Region-pinned
ISO 27001 + SOC 1/2/3 · HIPAA · FedRAMP

The trust thesis: outsource what's already best-in-class (Azure infrastructure, Assembly app surface), engineer the rest yourself, audit it, and publish what you find.

Compliance roadmap

SOC 2 in flight. Dates, not vibes.

Most pre-SOC-2 vendors say "compliant." We say "in flight" with target dates and a published list of what's done versus what isn't. Below is the actual plan.

Today · May 2026

Engine audited. App + Infra inherited.

Fail-closed defaults across 8 boundaries. External audit complete.

  • 15 of 15 external findings closed (April 2026)
  • HMAC, SSRF, path-traversal, PII redaction live
  • SOC 2 inherited via Assembly app surface
  • ISO 27001 + SOC 2 inherited via Azure infra
Q1 2027 · Target

SOC 2 Type I

Point-in-time attestation that controls are designed correctly.

  • Drata or Vanta as the controls platform
  • Control framework formalized + auditor selected
  • Policy library published (NDA-gated)
  • Background checks + JML formalized
Q4 2027 · Target

SOC 2 Type II

Operational attestation across a 6-9 month observation window.

  • Continuous evidence collection live
  • Tabletop IR exercises on cadence
  • Annual policy review completed
  • Pen-test cadence formalized

Other frameworks · status

GDPR Inherited Aligned via Assembly. DPA available on request.
CCPA Inherited Aligned via Assembly.
HIPAA Inherited Assembly + Azure aligned. BAA on request, case by case.
ISO 27001 Inherited Azure infrastructure. Ditto-direct certification not on roadmap.
FedRAMP Inherited Azure FedRAMP High. Ditto-direct authorization not on roadmap.

Engine · Ditto

Ten controls. All in production.

Ditto processes untrusted data: webhook payloads, CSV records, template references that fire network requests and run a headless browser. The threat surface is large. Every defense below is fail-closed by default and audit-verified.

01 § Auth

Authentication & authorization

API keys with explicit scopes (read, write, admin). Dashboard keys separate from service keys. No password-based access, ever.

key:scope no passwords
02 § Secrets

Per-client secret isolation

One credential per client, scoped to that client's data only, stored under a per-client environment variable. A leaked credential exposes one client, not the portfolio.

1 : 1 blast-radius bound
03 § Webhooks

Webhook signature verification

HMAC-SHA256 over the exact raw request bytes (not a re-serialization). Constant-time compare. Mis-signed = 401, no exceptions. Inbound and outbound.

HMAC-SHA256 constant-time raw bytes
04 § SSRF

SSRF defense

Every network request from the headless browser is intercepted at the Playwright layer. Schemes restricted to file, data, blob, and allowlisted https. Hostnames canonicalized, DNS re-checked against private IP ranges.

scheme allowlist canonicalize DNS recheck
05 § Paths

Path-traversal prevention

Template IDs match a strict allowlist of characters. Filename components are sanitized for traversal sequences, null bytes, and OS-reserved characters. Resolved paths are re-verified under the expected base directory.

char allowlist resolved-path guard
06 § Validation

Input validation on every boundary

Zod schemas validate every API request body. Unknown fields are stripped. String lengths capped, numeric ranges enforced. A round-trip test forces every new option to be plumbed end-to-end before merge.

Zod drift-prevention test
07 § XSS

HTML injection prevention

Record data is HTML-escaped before injection. Image src values run through a safe-scheme guard. Preview server uses a JSON data island plus per-request CSP nonce so injected scripts can never execute.

escape CSP nonce JSON island
08 § Logging

PII-safe logging

Structured logs via pino. Known PII fields (name, email, phone, ssn, token, secret, etc.) are auto-redacted. Full record payloads are never logged. Production error responses are redacted to a request-ID reference.

pino redaction allowlist request-ID
09 § Limits

Resource limits

JSON body cap (default 10 MB). Per-render timeout (30 s static, auto-scaled for video). Hard ceiling on concurrent Playwright pages. Rate limiting (200 req/min prod) with standard Retry-After headers.

body cap timeout rate-limit
10 § Tokens

Review-token security

Client-review URLs use 256-bit tokens (crypto.randomBytes(32)). Referrer-Policy: no-referrer on every response, expiry windows, manual revoke, one-shot on submission. Per-asset basename check on every fetch.

256-bit no-referrer revocable

Layer 2 · App surface

The customer-facing experience runs on Assembly.

Client review and approval, file uploads, intake forms, messaging, and billing all happen inside Assembly. We picked it because the security posture comes built in: SOC 2 attestation with continuous control monitoring by Secureframe, plus alignment with GDPR, CCPA, and HIPAA. We don't reinvent any of that.

Inherited via Assembly

What you get when your data is on the app surface

Every claim below is a published Assembly control. None are paraphrased; all are verifiable on Assembly's own trust portal.

  • SOC 2 attestation
  • Secureframe continuous monitoring
  • GDPR, CCPA, HIPAA alignment
  • Encryption at rest + in transit
  • MFA on all employee access
  • Background checks + JML policy
  • Annual security awareness training
  • Vendor risk reassessed annually
  • Incident response with tabletop testing
  • BC/DR plan with regular testing
  • Network traffic monitoring
  • Unique IDs + least-privilege access
  • Annual asset inventory review
  • Dev/stage/prod environment segregation
Read Assembly's trust portal

Why we don't run our own app surface

  • Posture before product. Building a SOC 2-attested app surface from scratch is 12-18 months of work that doesn't make Ditto a better rendering engine.
  • Auditable subprocessor. Assembly publishes its policies, its sub-processors, and its monitoring vendor. Your TPRM team gets one more vendor packet, not a black box.
  • Boundary-clean. Customer review, file uploads, and billing live in Assembly. Rendering and delivery live in Ditto. The seam is the integration, and the integration is documented.
  • You inherit Assembly's posture for the part of Ditto where your data interacts with humans. The engine adds its own posture for the part where data interacts with code.

Layer 3 · Infrastructure

Microsoft Azure, with the paranoid defaults turned on.

Production runs on Azure because Azure ships with the strongest hyperscaler security baseline available. We turn on customer-managed keys, deny-all egress, and a separate delivery domain. We don't take any "off by default" feature for granted.

01

Azure Container Apps

Renderer + dashboard run as managed containers. Stateless renderer architecture means horizontal scale across regions when needed. No host OS for us to forget to patch.

compute
02

Azure Blob Storage with customer-managed keys

Rendered assets land in encrypted Blob containers. Encryption keys are customer-managed via Azure Key Vault, not Microsoft-managed defaults. Output mounted on encrypted storage even before Blob, in dev.

data-at-rest
03

Azure Front Door

TLS termination and reverse proxy for both the platform surface and the delivery surface. Native WAF rules layer over Ditto's own request validation.

tls + waf
04

Restricted egress

Container egress denies all outbound traffic by default. Only the specific services Ditto needs (Assembly webhook receiver, Airtable API, Anthropic, Azure Blob) are allowlisted at the network layer.

deny-by-default
05

Two-domain isolation

Platform surface ({client}.dittoditto.io, auth-gated) and delivery surface (cdn.dittoditto.xyz, unauth, cache-heavy) live on separate origins. A misconfigured public asset URL can't leak admin auth state.

origin split
06

Region pinning + audit log

Compute and storage pinned to a named Azure region. Render-runs SQLite is a full audit log of every job that ever ran. Structured logs forward to a SIEM via Azure Monitor.

audit + region

Why Microsoft Azure

The largest security baseline of any hyperscaler.

Azure inherits the broadest portfolio of attestations in the industry, the deepest customer-managed-key tooling, and a first-party WAF and reverse proxy that integrate without third-party glue. You don't have to trust us to have configured the floor correctly. Microsoft already did, and they publish the floor plan.

  • Inherited certifications. ISO 27001, ISO 27017, ISO 27018, SOC 1, SOC 2, SOC 3, HIPAA, FedRAMP High, PCI DSS, plus 90+ regional and industry frameworks.
  • Customer-managed keys are first-class. Key Vault integrates natively with Blob, and key rotation is a single API call.
  • Front Door + WAF in one. No separate CDN-plus-WAF stack to misconfigure.
  • Region pinning enforced. Container Apps and Blob containers are bound to a named region; data residency is set at provision time.
  • Native SIEM integration. Azure Monitor pipes structured logs into your existing observability stack.

Inherited certifications via Microsoft Azure. Each of these covers the underlying compute, storage, and network we deploy on. Available on Azure's published trust documentation.

ISO 27001 ISO 27017 ISO 27018 SOC 1 SOC 2 SOC 3 HIPAA FedRAMP High PCI DSS CCPA GDPR + 90 more

Threat model

What we defend against, mapped to defenses.

Ditto is an internal service today, but we engineer it as if it were internet-facing. Every threat below has a named defense, a specific control, and a place in the codebase you can ask about under NDA.

Threat scenario Primary defense Control ref
Malicious webhook HMAC-SHA256 signature on raw bytes; constant-time compare; WEBHOOK_ALLOWED_CLIENT_IDS gate on client.created events. § 03 · Webhooks
Malicious CSV HTML escape on text fields; isSafeImageSrc on image sources; per-column Zod validation on import. § 06 · Validation, § 07 · XSS
Malicious template (SSRF) Browser-level request intercept; scheme allowlist; canonicalized hostnames; DNS re-resolution against private IP blocklist. § 04 · SSRF
Misconfigured deploy enforceProductionPosture() at boot; missing API keys, CORS config, or webhook secrets refuse to start the process. § Fail-closed defaults
Path traversal Strict char allowlist on template IDs; sanitizeFilenameComponent; resolved-path guard verifies the final path is inside the expected base directory. § 05 · Paths
Resource exhaustion Body cap (JSON_BODY_LIMIT), per-render timeout, hard ceiling on concurrent Playwright pages, rate limiting with Retry-After. § 09 · Limits
Credential leakage Auto-redaction allowlist on PII fields in logs; full record payloads never logged; production error responses redacted to a request-ID; per-client secret isolation. § 02 · Secrets, § 08 · Logging

External audit log

15 findings. 15 closed. Receipts attached.

An external security review covered the codebase in April 2026. Below is the full table of findings, severity, fix PR, and current status. Most trust portals bury this. We publish it.

Severity Finding Fix PR Status
Critical Webhook filename write allowed path escape PR #60 Closed
Critical Webhook signature verification was opt-in PR #60 Closed
High Raw-body re-serialization broke HMAC PR #60 Closed
High Preview XSS via query params PR #63 Closed
High NODE_ENV defaults to development PR #59 Closed
High CORS defaults to accept-all PR #59 Closed
Medium client.created allowlist absent PR #60 Closed
Medium SSRF canonicalization incomplete PR #61 Closed
Medium isSafeImageSrc bypassed via non-http scheme PR #61 Closed
Medium Error messages leak internals in prod PR #64 Closed
Medium ffmpeg path validation missing on Windows PR #65 Closed
Low No npm audit in CI PR #64 Closed
Low WEBHOOK_SECRET unvalidated at boot PR #59 Closed
Low DoS via oversized JSON body pre-existing Closed
Low Preview enabled in prod by default PR #59 Closed
15 of 15 findings closed across 6 PRs · auditor name and full report available under NDA · next external review scheduled before SOC 2 Type I.

Sub-processors

Every vendor in the data path. Disclosed.

A sub-processor is any third-party service that may process customer data on Ditto's behalf. Below is the complete list. Each row links to that vendor's own trust documentation. Notify your TPRM lead of any new addition before we onboard one — we'll publish it here first.

Vendor Purpose Region Posture Reviewed
Microsoft Azure Production hosting (Container Apps), encrypted blob storage, Front Door TLS termination, network controls. US (default)
region-pinned
ISO 27001 SOC 1/2/3 HIPAA FedRAMP High GDPR Annual
Assembly Customer-facing app surface: client review, file uploads, intake forms, messaging, billing. US SOC 2 Secureframe GDPR CCPA HIPAA aligned Annual
Anthropic (Claude) AI-assisted template authoring (opt-in feature, off by default). Customer record data is not sent to Claude in production renders. US SOC 2 Type II GDPR no-train policy Annual
Airtable Customer data source when the client opts in. One Personal Access Token per client base; per-client environment variable. US SOC 2 Type II ISO 27001 GDPR Annual
Google Fonts CDN for typeface assets used in templates. No customer record data ever sent. Used at render time only. Global CDN ISO 27001 SOC 2/3 no-tracking Annual

Transitive sub-processors (via Assembly)

Assembly publishes the following vendors as part of its own posture. They process data only inside the Assembly app surface, not inside Ditto's engine. Listed here for completeness so your TPRM review covers the full dependency tree.

  • AWS
  • Vercel
  • Sentry
  • PostHog
  • Stripe
  • Customer.io
  • Stream.io
  • Twilio · Segment
  • OpenAI

Incident response

When something goes wrong, here's the runbook.

A documented IR plan, tested on a regular cadence, with a published breach-notification SLA. Most pre-SOC-2 vendors keep this private. We'll send you the full playbook under NDA, but the contour is on the page.

Detect

Structured logs forwarded to a SIEM. Alerting rules on WEBHOOK_DELIVERY_FAILED, render failure rates, auth anomalies, and 5xx error budgets. /api/metrics per-error-code counts are scraped on cadence.

Triage

On-call acknowledges within 15 minutes. Severity classified per the IR runbook (P0 customer data exposure, P1 service down, P2 degraded, P3 cosmetic). Request IDs link every log line back to a job, a client, a render.

Contain

Per-client API key revocation is single-call. Per-token revocation on the review surface is single-call. Network egress allowlist and feature flags are tightened first; root-cause analysis follows.

Remediate

Fix lands as a PR with a regression test that fails on the original input. Backports to long-running deployments. Deploy through the standard pipeline; no out-of-band hotfixes.

Disclose

Affected customers notified within the SLA. Post-incident review published internally within 5 business days. Customer-facing post-mortem available on request, with a published lessons-learned distribution to the team.

Breach notification SLA

72 hrs

Maximum elapsed time from confirmed breach affecting customer data to written notification. Aligned with GDPR Article 33; we won't take longer than the regulator would let us.

  • Detection target: within 24 hours of an exploitable event
  • Initial triage: within 15 minutes of alert
  • Tabletop cadence: quarterly
  • Lessons-learned: published to the team within 5 business days
  • Customer post-mortem: available on request, redacted only for other affected customers' details

Production hardening

The same checklist we run before every deploy.

Bible §8.14, verbatim. This is the gate every production deploy passes through, with the green-checked items already enforced and the in-flight items targeted for the SOC 2 Type I window.

NODE_ENV=production (or unset, both work — fail-closed default)

Live

API_KEYS set to a long random value with explicit scopes

Live

CORS_ORIGINS explicitly lists the dashboard's origin (no wildcard)

Live

WEBHOOK_SECRET set to a new random value, rotated from dev

Live

WEBHOOK_ALLOWED_CLIENT_IDS lists only the clients authorized to create new tenants

Live

ALLOW_REMOTE_ASSETS defaults to false; explicit per-domain opt-in via campaign manifest

Live

Run behind Azure Front Door with TLS termination and WAF rules

Provisioning

Container egress denies all outbound except specific allowlisted services

Provisioning

Output volume mounted on Azure Blob Storage with customer-managed keys via Key Vault

Provisioning

Structured logs forwarded to a SIEM (pino JSON via Azure Monitor)

Provisioning

/api/metrics not exposed publicly (dashboard-only, or scraped internally)

Live

Vulnerability disclosure & contact

Found something? Tell us first.

We treat security researchers as partners, not threats. Report responsibly and we'll work with you in good faith. The policy below is our public commitment.

Responsible disclosure policy

What we promise · what we ask

What we promise: we acknowledge every legitimate report within 48 hours, triage on a defined severity scale, share a fix or remediation timeline within 7 business days, and never take legal action against good-faith research conducted under this policy.

  • Acknowledgement: within 48 hours of receipt
  • Triage: within 7 business days, with severity assigned and a remediation plan
  • Fix window: 90 days for unrestricted public disclosure; longer windows by mutual agreement
  • Credit: on request, in our security acknowledgements
  • Safe harbor: no legal action against research conducted in good faith under this policy

What we ask: report through the official channel below, give us a reasonable window to fix before public disclosure, and don't access more data than is necessary to demonstrate the issue.

  • In scope: ditto.copilot.app, dittoditto.io, cdn.dittoditto.xyz, and any production endpoint operated by Ditto.
  • Out of scope: third-party services we depend on (Assembly, Microsoft Azure, Anthropic, Airtable). Report those to the vendors directly.
  • Excluded methods: social engineering of personnel, denial-of-service attacks, physical attacks against staff or property, and any disruption of customer data or service.

This policy is published in good faith. We'll iterate on it as the program matures. Last updated 2026-05-04.

How to reach us

Direct, monitored, and answered.

Vulnerability reports hello@dittoditto.io

Subject prefix Security — routes directly to the security responder.

Document requests SOC 2 roadmap, DPA, audit report

All available under NDA. Most TPRM packages return within 2 business days.

PGP key Available on request for sensitive disclosures.
Trust portal updates

This page is the canonical trust portal. Sub-processors, IR runbook revisions, and SOC 2 milestones are reflected here as they change. Last updated 2026-05-04.

Stop renting trust. Start owning it. Every claim above is on this page. The rest is a one-email NDA away.

Start a TPRM review