Skip to main content

Trust & Security

Align is built to be deployed inside engineering organizations that care about how their decision data is handled. This section documents the controls Align implements, our data-handling commitments, and the subprocessors involved.

Compliance status

We hold no certification. Our route is ISO 27001 (decided 2026-09-21). We have not engaged a certification body, and we won't tell you an audit is underway when it isn't. See Trust for the full position.

Architecture commitments​

  • Tenant isolation, application layer (enforced by default). For any authenticated request the tenant comes from the verified auth token, and a client-supplied x-tenant-id header can never override it. The header is only consulted when there is no auth context, which covers trusted service-to-service calls (authenticated with a shared service token) and demo mode - it is not reachable as an ordinary authenticated user. getTenantFromReq resolves authTenantId || headerTenantId, and that precedence is locked by a regression test.

  • Tenant isolation, database backstop. Row-Level Security policies are defined with FORCE on every tenant-scoped table. No table is exempt. Migration 139_tenant_subscriptions_definers_and_force.sql closed the last exemption (tenant_subscriptions) once the Stripe webhook and the provisioning path stopped needing an owner connection; both now use the three SECURITY DEFINER functions 139 adds for the statements that genuinely precede a tenant context (the Stripe subscription update, plus provisioning's two cross-tenant lookups), and per-tenant context for everything else. Those functions run as their owner, so they depend on the migration role being RLS-exempt; where it is not, the lookups return no rows and provisioning fails closed rather than leaking. Coverage is derived from the schema by infra/__tests__/rlsCoverageParity.test.ts, whose exemption list is empty. A CI test connects as the restricted, non-owner align_app role and asserts a real cross-tenant query returns zero rows. The backstop only takes effect once the application connects as that restricted role rather than the database owner - a table owner bypasses RLS regardless of FORCE. The installation guide walks a new self-host install through this after migrations run. It is automatic with rlsCutover.enabled, and manual otherwise: the operator sets the role's password and adds it to the database secret. See Installation. An existing install, including our own hosted deployment as we complete this rollout, follows RLS Cutover to switch over.

  • Encryption in transit. TLS.

  • Encryption at rest. Provided by your infrastructure (RDS/EBS storage encryption, S3 SSE, ElastiCache encryption) and configured by you. Align does not add an application-level cipher over general decision data.

  • Application-level encryption of secrets. OAuth connector credentials are encrypted with AES-256-GCM using a master key you control, and the service refuses to start without that key rather than storing them in plaintext. Two named opt-outs exist for local development. The chart renders AUTH_DEMO_MODE and defaults it to false; ALIGN_ALLOW_PLAINTEXT_TOKENS is not rendered by the chart at all. The shipped Docker Compose stack sets demo mode, so tokens are stored unencrypted there. Tenant LLM API keys are encrypted separately, at the database layer, using PostgreSQL pgcrypto with the same master key.

  • Key rotation. The OAuth-token master key rotates with zero downtime (dual-key decrypt plus a background re-encryption job). If you also store tenant LLM API keys, rotating the same master key requires a short re-encrypt step alongside the key-swap deploy, because pgcrypto has no multi-key fallback. See Encryption Key Rotation.

  • Source content retention. The extracted decision record drops the verbatim captured message shortly after analysis. Two paths currently retain raw content for longer: the connector capture buffer and historical import batches. A third, the S3 raw-event archive, is disabled unless you set S3_RAW_EVENTS_BUCKET and writes to a bucket you own. See Data Retention for the exact tables and windows.

  • PII redaction before LLM calls on analysis paths. Emails, phone numbers, SSNs, IP addresses, credit card numbers, proper names and API keys are redacted before text is sent to a language model on the decision-analysis, synthesis and historical-scan paths. Detection runs Microsoft Presidio (an NLP model, so PERSON is covered) followed by a regex pass, and it is on by default - ENABLE_PII_REDACTION disables it only when set explicitly to false. It runs at a single choke point before every completion, streaming and tool call. Corrected 2026-09-21: this previously said it does "not yet run on every conversational endpoint", which stopped being true at the ALI-304 choke point and had already been recorded as retired on the subprocessors page. The embeddings path is not covered by that choke point. You can also point Align at a local LLM, so chat inference stays in your network.

    Corrected 2026-08-06: this bullet previously said redaction was "pattern-based" and did not cover proper names. That described an earlier state in which Presidio was declared but never installed, so the live redactor was regex-only. Presidio is installed and running now; the sentence had outlived the defect it described.

Access control & auditability​

  • SSO via OIDC (including Azure AD / Entra ID and any OIDC-compliant IdP) and Google; AWS Cognito federation. SAML 2.0 sign-in is built and off by default. It has been tested with a throwaway identity provider and not yet against a live Okta or Entra tenant, and only sign-in started from Align works - talk to us and we will run that setup with you. See SAML sign-in.
  • SCIM 2.0 provisioning (/Users and /Groups, including PATCH and deprovisioning).
  • Role-based access control with directory-group-to-role mapping.
  • An audit trail of mutations and access-control denials, retrievable by org admins via a filterable audit-log API. The application only ever inserts into it, and the database enforces that: update, delete and truncate on the audit table each raise, including for the table owner. Getting round it takes a deliberate schema change such as disabling the triggers. Legal hold applies to decision snapshots, not to audit records.
  • Per-user data export and deletion endpoints (GDPR Articles 17 and 20), with legal hold. These are admin API endpoints; there is no self-serve UI for them. Corrected 2026-09-21: this said "Article 15/17/20". There is no separate Article 15 access endpoint. Both endpoints were broken until ALI-1127 fixed them on 2026-09-21; see Data Retention.

Reporting a vulnerability​

Email security@align.tech for responsible-disclosure contact and process. Corrected 2026-09-21: this previously linked to SECURITY.md on GitHub, which 404s for anyone outside the organisation because that repository is private. We send the policy on request.