Skip to content

Security model

A coding agent runs commands and edits files for a model. A prompt injection in a file, a web page or a tool result can try to make the model do harm. Garuda puts each action through checks that the model cannot turn off. This page gives the overview; the architecture has the full threat table.

Every tool call goes through one check before it runs:

  1. The team policy (if one exists) can deny a command, a path or a host. Nothing overrides it.
  2. Sensitive files (.env*, keys, cloud credentials) are blocked, also for reads and also through a symbolic link.
  3. Protected paths: write tools never change .git/.
  4. Deny rules always win over allow rules.
  5. Read-only tools run with no question. Commands in the OS sandbox run with no question.
  6. Allow rules and earlier answers for this session let a call run.
  7. Otherwise Garuda asks you, and shows the diff or the command. So a command outside the sandbox asks (and the question says so), unless an allow rule or an earlier answer for this session covers it. The strict profile forbids commands outside the sandbox.

Seatbelt on macOS and bubblewrap on Linux. A command in the sandbox:

  • reads every file except the secrets in your home folder (~/.ssh, ~/.aws, keychains, tokens);
  • writes only in the project, the temp folders and the package caches;
  • cannot write .git/hooks, .git/config or .garuda/, because they run or apply later outside the sandbox;
  • has no network, unless you open an allowlist;
  • cannot start apps on macOS, and sees only its own processes on Linux;
  • gets only a short list of environment variables, so API keys stay out.

Staged commands (0.17, off by default): with "commands": { "mode": "staged" }, a sandboxed command runs in a staging copy of the project. When it changes files that git tracks, you see the diff and apply or discard; nothing reaches the project without your answer.

When you list hosts (or presets such as npm and pypi), sandboxed commands reach them through Garuda’s own proxy. Another host asks first. IP addresses, private addresses and ports other than 80 and 443 are refused.

A managed file and ~/.garuda/policy.json set the rules for a machine or a team: denied commands, denied paths, a required sandbox, blocked hosts, allowed models and step and token limits. A project cannot change them, and they hold for subagents and hooks too.

The strict profile ("profile": "strict" in a policy file or in .garuda/settings.json) requires the OS sandbox. Without one, Garuda stops at startup and does not run commands on your machine. The bash tool then has no outside_sandbox option. A project can turn the strict profile on, but not off.

A cloned repository can carry hooks, MCP servers, slash commands, skills, agents and settings. Each one that can run code or loosen safety asks once and shows its full content. The answer is pinned to a hash in ~/.garuda/trust.json, so a change asks again.

Every permission decision, tool run and hook command goes to ~/.garuda/audit/, outside the project. Secrets are redacted. Each line is chained to the one before by a hash, and /audit verify finds a changed, removed or inserted line. With the checkpoint ("audit": { "checkpoint": true } in a policy file), it also finds lines cut from the end of a file and a deleted file. The log is tamper-evident, not tamper-proof: someone who can write the files can rewrite a log and its checkpoint together. Sandboxed commands cannot write there.

The open limits of each release are listed in the README. To report a problem, see SECURITY.md.