Grinta Security Checklist

July 8, 2026 · View on GitHub

Grinta is local-first and runs with your user privileges. It is not a sandbox. Read this before pointing it at code you do not fully trust.

Threat model

  • In scope: untrusted prompts in trusted code; trusted prompts in trusted code.
  • Out of scope: untrusted code (e.g., a freshly cloned repo containing malicious build scripts), multi-user isolation, remote attacker scenarios.

Before each session

  • I trust the repository (no malicious package.json scripts, no rogue Makefile, no .envrc I didn't write)
  • My settings.json does not contain the only copy of any secret — store real keys in environment variables or a sibling .env file and reference them with ${VAR} in settings.json (see backend/core/config/api_key_manager.py)
  • I have a clean git working tree (so git diff is meaningful as an audit trail)
  • I know my autonomy level (/autonomy) — conservative for unfamiliar repos, balanced (default) for normal work. Grinta prompts on first open of a new workspace.

Built-in protections

ProtectionWhat it does
Runtime critical-command gateBlocks CRITICAL-classified shell and terminal commands while security enforcement is enabled
Hardened-local policyWhen security.execution_profile is hardened_local or sandboxed_local, blocks workspace escapes, package installs, network-capable commands, background processes, and sensitive path access unless explicitly allowed
Autonomy confirmation gate`/autonomy conservative
Audit logEvery action logged to ~/.grinta/workspaces/<id>/storage/<session>/audit/ with risk classification
Secret maskerKnown secret patterns stripped from output before display/logging
Shell guardDetects rm -rf /, force pushes, encoded payloads, privilege escalation, network exfiltration
File viewer scopingLocalhost-only file preview server rejects paths outside configured workspace roots

Read-outside-workspace (allow_read_outside_workspace)

  • Default is off. When enabled, only paths listed in additional_read_roots become readable (not the whole filesystem).
  • A sensitive-path deny list always blocks common secret locations (.ssh, .env, .npmrc, .docker/config.json, …).
  • Shell bypass: file-read tools honor the boundary, but Agent-mode shell commands (cat, Get-Content, …) do not. Use hardened_local or conservative autonomy on unfamiliar repos.

What Grinta is not

MisconceptionReality
A sandboxPattern matching can be bypassed by clever prompt injection or obfuscation
Isolated from filesystemhardened_local enforces Grinta policy checks, but actions still run with your host-user permissions
Safe against malicious buildsAuthorized tools (e.g., npm install on untrusted package.json) can trigger malicious scripts

Hardening recommendations

  • Run untrusted repos in a VM or container (disposable Docker or fresh user account with limited ACLs)
  • Use conservative autonomy for unfamiliar repos
  • Review the audit log (~/.grinta/workspaces/<id>/storage/<session>/audit/) after long sessions
  • Scope API keys to per-project with low spend limits
  • Pin Grinta to a known version in production-adjacent workflows; track CHANGELOG.md
  • Disable network-using commands when working offline (security.allow_network_commands: false in settings.json)

Trust boundary: settings.json and plugins

Grinta reads settings.json and any installed plugin source at startup and trusts them as part of the trusted compute base. Two surfaces in particular execute Python code on import:

  • agent.classpath — when an agent block has a classpath field, Grinta does importlib.import_module(<classpath>) to load the agent class. Any Python module whose dotted path you put in classpath will have its top-level code run at config load. Treat settings.json like a Python file: only let trusted sources write it.
  • agentskills plugin loader — Grinta's plugin loader (backend/execution/plugins/agent_skills/) statically imports skill modules. There is no permission model or sandbox. A skill is a Python function with full process privileges. Do not install skills from untrusted sources.

The same rule applies to the MCP servers you enable under mcp_config.servers: each command is spawned as a child process. The risk is the server itself, not Grinta's loader, but the trust boundary is identical — only enable MCP servers you have read the source of.

Reporting a vulnerability

See SECURITY.md. Do not open a public issue.