Ctrl K
ComunidadGuías…

SECURITY.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# 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, `<channel source=…>`) 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/<plugin>/`; a trusted project's `.noeta/plugins/<plugin>/` 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.