# Security Policy noeta runs agents that execute real tools — shell commands, file edits, web requests, MCP servers — on the machine that runs them. We want security reports, and we want them privately. ## Supported versions `noeta` and its terminal UI `noeta-tui`, released together on PyPI at the same version. Fixes land on `main` and ship in the next release; there are no backports. | Version | Supported | |---|---| | latest `main` | yes | | the newest 1.x release | yes | | 0.x (`noeta-runtime` / `noeta-sdk`, up to `v0.6.42`) | no — a different codebase | ## Reporting a vulnerability **Do not open a public issue for a vulnerability.** Report it through GitHub's private vulnerability reporting: the repository's [Security tab → Report a vulnerability](https://github.com/initxy/noeta/security/advisories/new). If you cannot use GitHub advisories, email `initxy0@gmail.com`. A useful report says what the issue is, the commit or version, a reproduction, and the impact you think it has. We aim to acknowledge within a few business days and keep you updated; please give us reasonable time to ship a fix before disclosing. We are happy to credit you. ## The security model What noeta defends, so you can tell a vulnerability from intended behavior: - **Model output and task input are untrusted.** They drive tool calls, so every call goes through the permissions plugin's gates (Claude Code's permission modes and `allow` / `ask` / `deny` rules; deny always wins, including over a hook or an approval). A way for model output to run a command, write a file, or reach a host that the rules and mode should have stopped is a vulnerability. - **`@path` mentions read only what the model could read without asking.** A file the task owner mentions is attached only when the permission check would let the model's own `Read` of it through without asking (inside the working directories, or under an allow rule); otherwise the model is told which file was mentioned, and its `Read` goes through the normal approval. A message a channel posts (`deliver` frames it as Claude Code frames channel messages, ``) is never expanded, and `~` is expanded only by a front end on the person's own machine, never on a server. An attachment that reads something the rules would have asked about is a vulnerability. - **The sandbox** (`sandbox.enabled` in settings: bubblewrap on Linux, Seatbelt on macOS) confines `Bash` to the working directory and allowed paths, with network only to allowed domains through a filtering proxy. Paths that would run code later without a person's confirmation (`.noeta/`, `.git/hooks`, `.git/config`, what points git at other config or hooks — `.git/commondir`, `.git/modules/` — and package-manager and build-tool settings) stay read-only, and missing ones are covered by empty read-only placeholders so they cannot be created; on Linux a `.git/commondir` the command creates is removed when it ends (git cannot run with an empty one). An escape from the sandbox, or a write to one of these paths from inside it, is a vulnerability. Without the sandbox, commands run with your user's rights after approval — that is intended. - **An untrusted project configures nothing.** A cloned repository's `.noeta/` settings, agents, prompts, skills and plugins load only after `noeta trust`; its MCP servers start only with consent in its own settings. Its instruction files (`NOETA.md`, `AGENTS.md`, `.noeta/rules/`) are read without trust, as Claude Code reads `CLAUDE.md`: they are text for the model, which configures and runs nothing, so they are untrusted input like the rest of the repository. noeta never reads Claude Code's own files (`~/.claude`, `.claude/`, `CLAUDE.md`, a project's `.mcp.json`). The one `.mcp.json` it reads is a Claude-Code-format plugin's own, inside a plugin directory in noeta's plugin places (`~/.noeta/plugins//`; a trusted project's `.noeta/plugins//` never starts its servers, and noeta tells you to copy them into the project's `.noeta/mcp.json`, which needs that project's consent). - **`noeta serve` always requires a bearer token** (`NOETA_SERVER_TOKEN`, or the one made on first start into `~/.noeta/server-token`, owner-only, and printed in the address at every start); `--no-token` is accepted only on a loopback address. Only the WebSocket route also takes the token as `?token=` (a browser cannot set the header there); `noeta serve` logs it as `REDACTED` (host code serving `create_app` calls `noeta.host.http.redact_token_logs`). Other web origins are refused, and so are `Host` headers other than the loopback names, those named with `--allow-host` and, on a bind that is not loopback, this machine's own hostname, fully qualified name and addresses. No request may start or switch a task into `bypassPermissions` unless the server allows it; a request sets only the task config and signals a client may. A task may run in any directory the server's user can reach: the token holder can run any command as that user anyway. A way around any of this is a vulnerability. - **One server serves one party.** Everyone holding the token has the same rights, and every task's tools run as the worker's OS user. To keep parties apart, run a server (and store) per party, or isolate commands with the sandbox or a container exec env. - **Plugins are code you install.** They run in-process with noeta's rights; installing one (`noeta plugin add`, a plugin file, a package) is trusting it. noeta runs nothing from a plugin while installing it, and a machine policy (`/etc/noeta/config.toml` `[policy]`) can allow or block plugins by name. The policy matches the name a plugin declares, not the file, package or repository it came from, so a blocked plugin under another name is not blocked (an allow list is what admits only known plugins). - **Nothing is sent anywhere by default** except requests to your configured model provider. - **Secrets** in configuration are written as `{env:NAME}` or `{keyring:service/user}` references and resolved only when a plugin is made, so they stay out of files and task logs. Out of scope: what a person explicitly approves or configures (`bypassPermissions`, broad allow rules, `dangerouslyDisableSandbox` approvals), the behavior of a model provider, and attacks that need write access to `~/.noeta` or the store.