Security at Kico
Last updated: October 21, 2026
Kico runs AI agents that write and execute code, use your connected accounts and send mail. This page describes how Kico is built to contain that. It describes what the system does today. Kico does not currently hold third-party security certifications such as SOC 2 or ISO 27001.
To report a vulnerability, write to hello@kico.dev.
Infrastructure
- Kico runs on Microsoft Azure in the South Central US region. Kico’s control plane, its database and the Docker host for sandboxes run as separate workloads.
- Network policies limit what each part may reach. Kico’s control plane reaches its database and the internet, but not the rest of the cluster and not cloud metadata endpoints.
- Releases are built from tagged commits and rolled out automatically, without restarting running sandboxes.
Sandbox isolation
- Every project runs in its own container, and every user’s assistant runs in its own container with its own private storage.
- Sandboxes run on a separate Docker host. Only Kico reaches its Docker API, over mutual TLS. Your sandbox never gets access to a Docker daemon.
- Sandboxes are on a network where container-to-container traffic is disabled, so one sandbox cannot reach another. They cannot reach Kico’s database, other services in the cluster, or the server’s own network. They can reach the internet and Kico’s own API.
- Each sandbox has memory and CPU limits.
- Each sandbox authenticates to Kico with its own token, which grants only what that project or assistant may do.
Secrets and credentials
- Envelope encryption. Model API keys, model subscription tokens, Git tokens, connector OAuth tokens, database passwords and user secrets are sealed with AES-256-GCM. Each user, each organization and the platform has its own random data key. The purpose of each value is bound into the encryption, so a value sealed for one use cannot be opened as another.
- Master key outside the database. Data keys are wrapped by a master key kept in Azure Key Vault and given to Kico at runtime. A database backup alone cannot decrypt credentials. The master key can be rotated; Kico re-wraps every data key on start.
- Credentials stay in the control plane. Sandboxes call AI models through Kico’s model proxy and connectors through Kico’s connector gateway; Kico adds the key or token on its side. Provider keys, subscription tokens and connector tokens never enter a sandbox and are never sent back to the browser.
- Egress proxy for app secrets. An app in a sandbox gets a placeholder (
kico-secret:NAME) and a proxy address. Kico adds the real value on the way out, and only for the hosts that secret is meant for. Secrets that cannot be proxied become environment variables, and Kico hides their values in tool output and in what it streams to the browser. - Models see names, not values. When a model needs a secret, it asks for it through a masked form in the UI. A secret pasted into a message to the assistant is detected, moved into the vault, and replaced with its name.
- Database access. Data source credentials never reach a sandbox. Agents and apps query through Kico, read-only, with row limits and time limits, and every query is logged. SQLite files are opened in a separate process that is stopped at the time limit.
- Hashed tokens. Invitation and password reset links are 32 random bytes; only their SHA-256 hash is stored. Share links are stored hashed.
Authentication and sessions
- Passwords are hashed with scrypt and a random salt.
- Sessions are HMAC-signed cookies, valid for 30 days, marked HttpOnly and SameSite=Lax, and over HTTPS Secure with the
__Host-prefix (bound to the exact host). Changing your password signs out every session. - Sign-in with GitHub works only for accounts that linked GitHub while signed in to Kico, by GitHub’s numeric user ID, never by email. The sign-in state is bound to the browser that started it, with PKCE.
- Rate limits apply to sign-in, password resets, email changes, guest confirmation codes and dictation.
- Invitations expire after 7 days and work once. Password reset links expire after one hour and work once.
- Project previews run on separate hosts. Kico gives each preview a short-lived grant that the preview host exchanges for its own cookie, and every preview request re-checks that you may still open the project. Guests on share links get a cookie for that preview host only and never reach Kico’s own UI or API.
Authorization
- Roles per organization (Owner, Admin, Member, Viewer) and per project (Can use app, Can edit) are checked in one place on the server. A project is private to its owner until shared; Owners and Admins do not see projects that nobody shared with them.
- Platform administration routes are listed in one table, each with its required permission, and checked against the target’s scope before running. Outside an administrator’s scope, resources answer as not found.
- When a Kico administrator signs in as a user for support, the session lasts at most one hour, cannot be nested, and excludes the user’s password, API keys, model servers, Git connections, Tailscale, data source credentials, secrets and invitations. The user’s connector reads do not run during it. Start, end and every change are written to the audit log, and the user sees every such session under Account, Security.
Approvals for outward actions
Kico distinguishes work you asked for from work something else started.
- Connector writes. A connector tool counts as read-only only when the vendor marks it read-only and not destructive; anything else is a write. Writes run at once when you asked for the work (your latest message, or a schedule you made). When an event started the work (an incoming mail, a project event, a question from another agent), the write is held until you choose Run, Change or Don’t run, unless you created an “acts without asking” rule for it. Only you can create such rules; the assistant can create one only right after your own message asking for it, never from an event.
- Mail. Mail from your assistant to people outside your organization always waits for your confirmation, even when you asked for it, unless a “sends without asking” rule you created allows those recipients for work started by a mail. Mail to colleagues goes at once only when you asked for it or a schedule you made sent it. Work started by an incoming mail cannot mail colleagues or outsiders without your confirmation unless such a rule allows them. Unconfirmed mail is never sent and expires after 24 hours.
- Kill switch. One control stops all running assistant work, including project work it started, and pauses it.
Connector security (SSRF protection)
Every outbound request Kico makes for connectors (discovery, OAuth, MCP calls, icons) goes through a guard that:
- allows HTTPS only and no credentials in URLs;
- refuses private, loopback, link-local, carrier-grade NAT, multicast and reserved addresses, including IPv4 addresses embedded in IPv6;
- resolves names inside the connection, so a name that resolves to an internal address is refused at connect time;
- follows redirects by hand, for GET only, checking each hop;
- limits response sizes.
OAuth follows the MCP authorization specification: PKCE S256, a random state bound to the signed-in user, the resource parameter, issuer checks (RFC 9207), and rotating refresh tokens. Disconnecting revokes tokens at the vendor where the vendor supports revocation. Connector answers are scanned for the connection’s own tokens, which are replaced with “[redacted]”. Untrusted files (mail HTML, connector icons, downloads) are served with restrictive Content-Security-Policy and nosniff headers; only images, PDFs and plain text open inline.
Agent mail
- Kico receives mail for agents.kico.dev on its own SMTP server; no third-party mail service is involved in receiving. It offers STARTTLS with a Let’s Encrypt certificate.
- Every incoming message is checked for SPF, DKIM, DMARC and ARC. A sender counts as verified only on DMARC pass; a DMARC failure is shown as a possibly forged sender. Agents see these results.
- Unknown recipients are rejected. Limits apply per sender per hour, per mailbox per day, per message size and per number of recipients.
- Outgoing mail is sent through Azure Communication Services from kico.dev, which publishes SPF, DKIM and DMARC (
p=quarantine).
Audit and activity logs
- The audit log records every platform administration action and every change made while an administrator is signed in as someone: actor, subject, action, target, time and IP address. Entries are only added, never edited.
- The assistant’s activity log records every tool call; actions that reach other people are listed as “Actions on your behalf”. Connector calls are logged with the tool and outcome, not the content.
- Token usage is recorded per user, organization, project and task.
Encryption
- In transit. The web app, API and previews are served over HTTPS with certificates from Let’s Encrypt; HTTP is redirected to HTTPS. The connection to the sandbox Docker host uses mutual TLS. Calls to AI providers and connector vendors use HTTPS.
- At rest. Credentials are sealed by Kico as described above. Azure encrypts the underlying managed disks and storage at rest.
Backups and recovery
- Disk snapshots of the server (both disks) every 4 hours, with daily recovery points kept 30 days, in an Azure Recovery Services vault.
- A nightly logical backup of the database to Azure Blob storage, kept 14 days, written with a write-only access signature.
- The master key is kept separately in Azure Key Vault; backups do not contain it.
Monitoring
Uptime is checked from several locations every five minutes, along with certificate expiry, machine health, CPU, memory and disk. Kico watches sandbox memory, restarts and out-of-memory events and alerts the operator.
Data retention and deletion
See the Privacy Policy for what is kept, for how long, and how to delete it.