Kotoba

Where to start

What Kotoba isWho she is and where she runs, in one page
InstallingOne package, two commands
First runA key, a model, her first words
The approval gateHow she asks before she acts
The two voice modesLocal voice, or the agent tunnel
The soul fileChange who she is
RoadmapWhat grows next, and what was cut on purpose

Or a section

↑↓ move openesc close124 pages
All pages

Security1 of 10

The security model

About 4 minutes to read

On this page

Kotoba runs on your machine. It holds your API keys, reads and writes files, and — on the default setting — runs shell commands and Python as your own user account.

This section says exactly what stops what, and, with the same care, what does not. Every claim on these pages was checked against the code, and where the code protects less than the wording elsewhere suggests, the page says so.

The four things that decide what she can do

ControlWhere it is setWhat it decides
KOTOBA_SANDBOXapi/.env, or Settings → SecurityWhether commands run on the host, in a container, or not at all
The approval gateNothing to configure; grants are saved as you answer cardsWhich commands run without asking you
The working directoryKOTOBA_WORKSPACE_DIR, default ~/.kotoba/filesWhere her file tools may read and write, and where a command starts
KOTOBA_WEB_PASSWORDapi/.env and .env.localWhether anything on the network can reach the API at all

A fifth is worth naming because its absence is the default: with no KOTOBA_WEB_PASSWORD set, the API is open to anything that can reach the port.

What actually protects you

A card in front of anything that runs. With KOTOBA_SANDBOX=local — the default — every shell command that is not a plain read inside the working folder stops and asks. Nothing runs before you answer. The exact line is drawn in The approval gate, measured rather than described.

A scrubbed environment. A child process started for her gets an allow-list of variable names and nothing else. Your provider keys are not among them, so a command or snippet she runs cannot read them out of its own environment. Measured on a Linux desktop: fifteen names reached the child, and OPENAI_API_KEY, ELEVENLABS_API_KEY and GITHUB_PERSONAL_ACCESS_TOKEN — all present in the parent — did not. The list is enumerated in Secrets.

A path jail on the file tools. Every path her file tools receive is resolved — symlinks and .. included — and refused if it leaves the working directory (core/path_security.py).

Encryption at rest for keys you save in the app. AES-256-GCM, with the master key in a separate file at mode 0600. See Secrets.

A closed API when you close it. One password shuts both the web surface and the model endpoint. See The web gate.

A guard on every URL she can be steered to fetch, and a screen over third-party tool text before it reaches the model. See Fetching and third-party content.

What does not protect you

The working directory is a starting point, not a cage. On KOTOBA_SANDBOX=local an approved command runs as your own user account, with your own file permissions. It begins in the working folder, and the auto-approval rules refuse to run a read whose arguments point outside it — but a command you approve can read anything you can read. Measured: a command run through the local backend printed /etc/hostname and listed /etc without difficulty. The word "sandbox" in the setting's name describes where a command starts and what environment it is handed, not a kernel boundary. Only KOTOBA_SANDBOX=docker is isolation.

Writing a file does not ask. write_file and patch write inside the working directory with no approval card. They are jailed to that directory and they are recorded in the audit trail, but nothing pauses for you. Since the working directory is the Files library by default, that includes overwriting a file already in it.

The dangerous-command list is a denylist over text. It is a set of 14 regular expressions read over the command line. It catches the shapes it names and nothing else. See Dangerous commands.

The Python pre-screen is a denylist over source. Same class of thing, 7 patterns, for execute_code. It is a speed bump, not a wall. See execute_code.

Reads are not audited. The audit trail records tool calls whose risk is write, exec or network. Searching the web, fetching a page and reading a file are read and leave no row. What she read is in the conversation, not in the log.

Settings → Security shows a trust field that does nothing. It is read from KOTOBA_TRUST and displayed; no code path consults it. api/.env.example labels it "Display-only, not yet enforced". Treat it as a placeholder, not a control.

The default posture, stated plainly

A fresh install runs commands on your machine as you, asks before anything that is not a plain read, writes files without asking inside one folder, and serves an unauthenticated API on localhost. That is a reasonable posture for a personal assistant on a laptop you own. It is not a reasonable posture for a machine anyone else can reach.

If you want less: KOTOBA_SANDBOX=docker for real isolation, or none to withhold execution entirely. Set KOTOBA_WEB_PASSWORD before you expose a port. Both are covered in The sandbox setting and The web gate.

Pages in this section

  1. The approval gate — what asks, what does not, and the two kinds of grant
  2. Dangerous commands — the labels, and what a denylist can promise
  3. The sandbox settinglocal, docker, none
  4. execute_code — the Python path and its pre-screen
  5. Secrets — the keystore, file permissions, the scrubbed environment
  6. The web gate — passwords, cookies, CORS, the model endpoint
  7. What leaves your machine
  8. Fetching and third-party content — the URL guard and the MCP screen
  9. Reporting a vulnerability