Skip to content

Secure defaults

New installations start secure. Existing installations keep the behaviour they were set up with and are told, by kurahi doctor and at gateway startup, which settings still use an old permissive default. Nothing changes silently and nothing crashes.

kurahi init, kurahi setup and onboarding write these values when they create a fresh config (kurahi init --force counts as fresh). They never override a value that is already set.

Setting Old default (still the fallback when unset) New installations OWASP
auth.isolation inherit: every agent sees the main agent’s credentials explicit; the identity agent kurahi init creates gets auth.grants.<id>: ["*"], every other agent only what it is granted ASI03
agents.defaults.sandbox.mode off: no session runs in a container non-main with workspaceAccess: "rw": groups, channels, sub-agents and cron run in the container sandbox ASI05
tools.exec.unsandboxed host: where no sandbox is active, commands run on the host with no approvals approve: commands outside a sandbox go through exec approvals (allowlist, ask on miss) ASI05
Policy file (budgets, job limits) none: no budgets, no job limits the starter policy, signed with a local owner key (kurahi policy init) ASI08
integrity.supplyChain.mode warn: unpinned or modified skills and plugins load with a warning enforce: a non-bundled skill or plugin loads only when its SHA-256 is pinned in the signed lock (details) ASI04
memory.provenance.mode warn: memory writes are tagged and flagged, but writes after untrusted input still land enforce: memory writes after untrusted input (or that look like injected instructions) are held for review, see Memory provenance ASI06
agents.messaging.signing.mode warn: unsigned, forged, replayed or malformed inter-agent messages are delivered, flagged enforce: they are rejected (see Agent message signing) ASI07
console.terminal off: the console terminal methods refuse every request enabled: true, actApprovals: "always": every act-mode command that is not read-only waits for an approval (details) ASI05

Always on, for every installation: the destructive-command guard (below).

The starter policy (<KOLO_HOME>/policy/policy.yaml, source src/policy/starter.ts) sets:

Limit Value On breach
Concurrent jobs per agent 4 the next job is refused
Wall clock per job 30 minutes (1,800,000 ms) the job is stopped
Tool steps per job 200 the job is stopped
Tokens per agent per day 5,000,000 pause
Tool calls per agent per hour 1,200 pause
Fleet tokens per day 20,000,000 pause
Fleet tool calls per hour 5,000 pause

A pause holds new work for that agent (or the fleet) until the window resets, or until an operator runs kurahi policy release --agent <id> (or --all). Change the numbers by editing the policy and running kurahi policy sign; the gateway reloads it on save. Day windows reset at budgets.resetHourUtc (00:00 UTC by default).

The same starter policy also sets (checked on a fresh kurahi init, 24 October 2026):

Rule Value
data.neverRead ~/.ssh/**, **/.env, **/*.pem, **/id_rsa* and, since 2.1.0, <KOLO_HOME>/secrets/** (gateway token, owner key, secret store)
data.neverWrite ~/.ssh/**, /etc/** and, since 2.1.0, <KOLO_HOME>/secrets/**, <KOLO_HOME>/policy/**, <KOLO_HOME>/kolo.json, <KOLO_HOME>/audit/**
data.secretPatterns private-key headers and AWS access key ids refuse a call that carries them
network.egress.deny cloud metadata endpoints (169.254.169.254, metadata.google.internal); no allow list
shield.mode stop: decoy files and mass-encryption detection stop every agent
attestation.required true: an unsigned policy is refused in enforce mode
approvals.timeoutMs 120,000; an unanswered approval is a denial

~/ is the operating-system user’s home. The data lists apply to the file tools (read, write, edit, apply_patch, including the file_path alias) and the legacy analyser; commands are covered by exec approvals and the sandbox. A fresh kurahi init also writes the gateway token and the owner key with mode 0600 in 0700 folders, binds the gateway to loopback with token authentication, and grants the identity agent every credential (auth.grants.<id>: ["*"]).

Installations created before 2.1.0 keep their policy file. Add the <KOLO_HOME> entries above to data.neverRead and data.neverWrite, then run kurahi policy sign.

When a protection needs something that is not installed

Section titled “When a protection needs something that is not installed”

The sandbox needs a container runtime (Docker) and the sandbox image (scripts/sandbox-setup.sh). When a session must be sandboxed and the container cannot start:

  • the run continues; it does not fail;
  • exec is refused with the reason and the fix (install Docker, or set agents.defaults.sandbox.mode: off to run commands on the host through approvals);
  • file tools stay inside the agent workspace;
  • browser host control is off.

Exec never falls back to running on the host unprotected. kurahi init and kurahi doctor report a missing container runtime.

Project sessions (Desktop projects) are not put in the container: the project scope already confines them (files only in the project folder, writes only to its writable folders, exec never granted, see src/projects/scope.ts), and a container would hide the project folder.

Every path that turns agent output into a shell command checks it first against an unconditional blocklist (src/security/hardline-guard.ts): recursive deletes of /, system folders or the home folder, deleting KOLO_HOME or its vault, mkfs, dd or redirects to a raw block device, fork bombs, kill -1, shutdown and reboot, wsl --shutdown, killing the gateway, and sudo -S password guessing. The check normalises fullwidth characters, ANSI escapes and shell escape tricks first.

A blocked command is refused, never queued for approval. No allowlist, approval, elevated mode or security: full can run it. Every decision is written to the hash-chained audit log as exec.guard, denied with the pattern, or allowed (kurahi audit tail).

Wired into: the exec tool (sandbox, gateway and node hosts), process write, send-keys and paste, the nodes tool run action, system.run on node hosts, and the lobster plugin.

An installation whose config predates these defaults keeps working exactly as before. It gets:

  • a Secure defaults section in kurahi doctor, one item per unset setting with the fix;
  • secure-defaults.*, policy.present and supply-chain.lock checks in kurahi doctor --json;
  • secure defaults: warnings in the gateway log at startup;
  • a one-time warning the first time exec runs on the host without a sandbox and without tools.exec.unsandboxed set.

A setting that is set explicitly, even to the old value (for example tools.exec.unsandboxed: "host"), is treated as a decision and not warned about.

To adopt the secure defaults on an existing installation:

Terminal window
kurahi config set auth.isolation explicit
kurahi config set auth.grants.<your-agent-id> '["*"]' # the owner's own agent keeps all credentials
kurahi config set agents.defaults.sandbox.mode non-main
kurahi config set agents.defaults.sandbox.workspaceAccess rw
kurahi config set tools.exec.unsandboxed approve
kurahi config set agents.messaging.signing.mode enforce
kurahi policy init # signed starter policy
kurahi skills pin --all && kurahi plugins pin --all # review first: this approves what is on disk
kurahi config set integrity.supplyChain.mode enforce

Grant every other agent the profile ids it needs in auth.grants.<agent-id> before switching isolation on; an agent without a grant has no credentials under explicit.