← Ataski · Trust & security · DPA · Subprocessors

This is the canonical English version. Native translations for DE / ES / FR / PT / RU are pending counsel sign-off.

Approved 2026-10-08

Information Security Policy

Owner: the founder. Approved: 2026-10-08. Review: annually and after any incident. Applies to: everyone with access to Ataski systems or customer data — today, one person.

1. Why this exists

Customers hand Ataski their CRM, their accounting ledger, their contracts and their support inbox. Everything below exists so that data stays theirs, stays where they put it, and can be got back or destroyed on request.

This is not a template. Every rule names the mechanism that enforces it, so a rule that stops being true is a rule whose mechanism can be checked.

2. Scope

The production system: the Hetzner application node, the Neon Postgres database, Redis, Cloudflare R2 object storage, and the vendor accounts listed on /legal/subprocessors. Also the founder's workstation, because it holds the SSH key and the development .env.local.

Out of scope: nothing. There is no test estate holding real customer data — .env.local points at the production Neon instance, which is a known hazard and is why the test-tenant guard exists.

3. Standing rules

  1. Every tenant-keyed table is fenced by Row Level Security. No exceptions, no "the scheduler runs in admin mode" carve-outs. A guard in the pre-push gate replays every migration and refuses the push if a table with tenant_id lacks a policy (tests/test_rls_coverage_all_tenant_tables.py).
  2. The audit log is append-only. Enforced by database grants, not by convention: the runtime role holds SELECT and INSERT, and UPDATE and DELETE are explicitly revoked (migrations/versions/0177_audit_log_append_only_grants.py). Retention is discharged by scrubbing personal columns, never by deleting rows.
  3. Secrets never enter git. gitleaks runs on the staged diff in the commit hook (scripts/git-hooks/pre-commit) and over the branch and the whole history in the pre-push gate, which refuses the push on a finding. Both run on the founder's machine and nothing on GitHub re-checks; a finding is never pushed past with --no-verify — the credential is rotated instead. Production values live only in the server's .env, which the deploy script never writes and refuses to deploy with unless its mode is 0600 or tighter.
  4. All LLM traffic goes through the gateway. Business logic never calls a provider SDK directly; all external data reaches the workers through MCP tools. This is what makes per-role tool whitelists and per-tenant spend caps enforceable at all.
  5. Least privilege by default. The application connects as ataski_runtime, a role provisioned without BYPASSRLS and without DELETE on most tables. Destructive operations (the offboarding purge) require the owner connection deliberately.
  6. Nothing is claimed that cannot be shown. No "SOC 2 compliant", no certifications we do not hold, no security control described in the present tense while it is still a stub. Where a control is a roadmap item — per-tenant encryption keys, for example — the public page says so.

4. Roles

There is one role: the founder, who is simultaneously the security officer, the incident commander, the change approver and the only production operator. The absence of segregation of duties is disclosed rather than papered over; the compensating controls are that a change reaches production only as the whole origin/main ref (the deploy refuses anything else), merged through a pull request whose head passed the pre-push gate, and that every administrative action lands in the append-only audit log. The gate is not an independent witness: it runs on the author's machine, --no-verify skips it, and GitHub enforces nothing — there are no required status checks, and branch protection is not available for a private repository on the free plan (ADR-0119).

5. Classification

Two classes are enough at this size.

Credentials are a third thing: they are Customer Data that is never readable by anyone, including the customer's own export (src/ataski/data_classification.py marks them secret_columns).

6. Exceptions

An exception to any rule above requires an ADR in docs/adrs/ that states what is being weakened, for how long, and what compensates. "We will fix it later" is not an exception; it is an undocumented gap, and the readiness map (docs/security/soc2-readiness.md) is where those are listed honestly instead.

7. Enforcement

The git hooks are the enforcement mechanism for the technical rules: the commit hook runs the fast checks on the staged files, and the pre-push gate (scripts/check.py, ADR-0119) runs everything — ruff including the S security rules, mypy --strict, the test suite, gitleaks over the branch and the whole history, trivy fs with CRITICAL blocking, the migration chain and the live-schema suites, and the Schemathesis API fuzz. Both are installed once per clone with scripts/install_git_hooks.sh. For the human rules the mechanism is the quarterly self-review in docs/security/evidence-checklist.md: if a rule here is not observable in that review, it is decoration and should be deleted rather than kept for show.