1. Overview
Pandora is an autonomous AI agent fleet that operates on customer code. Because the fleet writes diffs, runs scripts, and opens pull requests, our security model has two layers: protecting customer data (the usual SaaS concerns) and containing the agent fleet (so a misbehaving agent can not exceed its authority). Both are described below.
- Transport: TLS 1.3 only, HSTS enforced, modern cipher suites.
- Authentication: session cookies with
HttpOnly+Secure+SameSite=Lax; optional magic-link sign-in. - Data residency: primary infrastructure in Switzerland; backups encrypted with GPG before leaving the host.
- Agent containment: three trust tiers, a capability airlock, and a kill-switch that halts the entire fleet in under a second.
- Reporting: a single inbox at security@pandora-ai.ch for responsible disclosure.
2. Transport and network
TLS 1.3 and HSTS
All public traffic terminates at Caddy, which we configure for TLS 1.3 only. Older protocols (TLS 1.0, 1.1, 1.2) are disabled on the listener. Caddy automatically renews certificates via Let's Encrypt for both pandora-ai.ch and customer subdomains (*.pandora-ai.ch). HSTS is set with a one-year max-age and the includeSubDomains directive so browsers will refuse to downgrade to HTTP.
Security headers
The backend applies OWASP-recommended response headers on every reply: a strict Content Security Policy with nonce-based script tags, X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: no-referrer, and Permissions-Policy denying camera, microphone, and geolocation. The CSP forbids inline event handlers and inline <script> blocks unless they carry the per-request nonce.
Loopback hygiene (P0 control)
Internal services that the fleet uses (Mission Control, the worker loop, the local llama bridge when enabled) bind to 127.0.0.1 only. They are never exposed to the public internet. Caddy is the single ingress point and rewrites paths before forwarding to the backend container. A startup guard refuses to launch the backend if AUTH_DISABLED=1 is set in production environments — that flag is for local development and would otherwise turn the dashboard into an open mailbox.
3. Authentication and sessions
Sign-in
Sign-in uses either email + password or a magic link delivered by email. Passwords are hashed with bcrypt at a work factor we tune to one second per check on the production host; the plaintext is never stored or logged. Per-IP login rate limiting blocks the same IP after five failed attempts in fifteen minutes, with a 429 response and standard Retry-After header.
Session cookies carry the three flags that matter: HttpOnly (so client-side JavaScript can not read them, which neutralises most XSS data-theft attempts), Secure (so the cookie never travels over HTTP), and SameSite=Lax (so cross-site form submissions can not carry the cookie except for top-level GET navigation). Sessions expire after a configurable idle window and refresh on each authenticated request.
CSRF protection
State-changing requests require a custom header (X-Pandora-Request: 1) that the frontend sets automatically. Because SameSite=Lax already neutralises cross-site POSTs, this header is the secondary defence and exists to fail closed on subtle browser quirks. Endpoints that accept HMAC-signed callbacks (peer coordination, Genie bridge) verify the signature inside the handler — they are exempt from session-cookie checks by design.
4. Data handling and residency
Where data lives
Primary infrastructure runs in Switzerland. The application database, agent output archives, and access logs all live on Swiss hardware. Switzerland's revised Federal Act on Data Protection (in force since 2023) provides strong protections, and the European Commission recognises Switzerland as offering an adequate level of data protection for EU personal data — so transfers from EU customers do not require additional safeguards.
Encryption at rest
The application database is SQLite running in WAL mode on encrypted disk. Snapshots are taken on a fixed schedule, compressed, and encrypted with GPG using a public key whose private half lives off-host. The encrypted archives are what we copy to off-site storage; the unencrypted snapshot never leaves the production host.
Retention
Access logs are kept for 30 days for security and abuse investigation and are then deleted. Account data and agent outputs are kept for the life of the account plus 90 days after cancellation, after which they are permanently deleted from the primary database. Backups follow the same lifecycle on a 30-day rolling window.
What we do not do
We do not train AI models on your repository content or your agent outputs. We do not sell or share customer data with advertisers. We do not embed third-party trackers on the dashboard. Sub-processors (the LLM vendors you choose, Stripe for billing once enabled, GitHub for repository access) are listed in our Privacy Policy.
5. Access controls and agent containment
Trust tiers
Every worker in the fleet carries a trust tier that gates what it can ship without human approval:
- supervised (default) — every task requires explicit approval from the account owner.
- trusted — can auto-approve low-risk changes (docs, tests, formatting).
- autonomous — can auto-approve low and medium-risk changes (feature code, refactors).
Tasks carry a risk_level of low, medium, or high. High-risk work (auth, secrets, deployments, migrations, CI/CD, self-modification) always requires owner approval regardless of trust tier. There is no escape hatch from this rule.
Capability airlock
When a worker needs a new tool or permission (write access to a new file path, a new shell command, a new network destination), the request lands in a capability airlock queue. The account owner reviews and grants the permission explicitly. The fleet can not silently expand its own authority — the airlock is the only path to new tools.
Role gating
Internal API routes use _require_role() for every authenticated endpoint. Roles include owner, approver, customer, and a tenant scope. Customer-portal routes additionally check tenant_id equality so one customer can never read another customer's data, regardless of session validity.
Kill switch
A single file flag halts the entire fleet in under a second. The worker loop polls this flag on every cycle; when it appears, in-flight tasks finish their current step and stop. This is the emergency brake we pull when something looks wrong — for instance, a deploy that destabilised behaviour, or a model regression that started shipping noise.
6. Security gates and monitoring
Rate limiting
All unauthenticated endpoints (login, waitlist signup, status subscribe, magic-link consume, public health) are rate-limited per IP inside the handler. Limits use a sliding window over a configurable horizon; abusers receive a 429 with Retry-After. The login limit (five failures per fifteen minutes per IP) is tracked in SQLite WAL so it survives backend restarts and is consistent across replicas.
AUTH_DISABLED production guard
The backend refuses to start in production if it detects AUTH_DISABLED=1 in the environment. That flag is a developer-mode bypass for local testing; running it in production would turn every authenticated route public. The guard reads the deployment environment from PANDORA_ENV and aborts startup with a clear error if both conditions hold.
Dependency hygiene
Python dependencies are pinned in requirements.txt and reviewed before every upgrade. Node dependencies (Mission Control) are installed with npm ci --ignore-scripts to neutralise lifecycle-script supply-chain attacks (the pattern used by the Shai-Hulud-class worms in 2025–2026). A weekly Security Auditor job watches kernel CVE patches landing in apt and flags drift in security-sensitive settings such as kernel.yama.ptrace_scope.
Logging and alerts
Every request gets a request ID and an authenticated structured log line. 401s, 429s, and 5xxs are sampled into a dashboard. Health probes from external monitoring run unauthenticated against /api/ping and /api/health; both return small JSON bodies and never expose internal detail. The status page at /status publishes anonymised health data so prospects and customers can see incidents without an account.
7. Reporting a security issue
How to reach our security team
Email security@pandora-ai.ch with a description of the issue, the steps to reproduce, and the impact you observed.
We acknowledge new reports within two business days and provide a triage update within five business days.
Please give us a reasonable window to investigate and remediate before disclosing publicly. We do not currently run a paid bug bounty but we publish coordinated-disclosure credits on this page after fixes ship.
For account compromise or data exposure concerns specifically, prefix the subject line with [URGENT] so it routes to the on-call rotation rather than the general queue.
8. Changes to this page
We update this page whenever a meaningful security control changes — new gate, new attestation, lifted limitation. The last-updated date at the top of the page reflects the most recent revision; older versions are retrievable from our git history on request.