opencode opencode.ai ↗
Open-source terminal agent from SST. CVE-2026-22812 (unauthenticated HTTP server RCE, fixed 1.0.216) and CVE-2026-22813 (markdown XSS, fixed 1.1.10). Plugin and MCP local servers execute arbitrary code at startup.
Patch and Audit the Install
CVE-2026-22812 (unauthenticated RCE via the local HTTP server — any malicious webpage could execute shell commands) is fixed in 1.0.216; CVE-2026-22813 (HTML injection in the markdown renderer, no DOMPurify/CSP) is fixed in 1.1.10. Anything older is exploitable from a drive-by browser tab.
--cors allowed cross-origin POSTs to /session/* endpoints. GitHub Advisoryopencode --version # require >= 1.1.10Tip: track GitHub Security Advisories on sst/opencode; uninstall old global binaries before installing the new one.
Keep the HTTP Server Private
opencode serve binds 127.0.0.1:4096 by default and exposes /tui, /session/*, and the full OpenAPI spec at /doc. Never bind to 0.0.0.0 or widen --cors to wildcards — that is the pre-1.0.216 RCE class.
OPENCODE_SERVER_PASSWORD='<long-random>' \
opencode serve --hostname 127.0.0.1 --port 4096Tip: leave --mdns off, set explicit --cors origins, front any remote exposure with an SSH tunnel or mTLS reverse proxy.
Enforce Gateway/Basic Auth on Server Mode
The server is unauthenticated unless OPENCODE_SERVER_PASSWORD is set. Without it, anything local — including a browser page hitting localhost — can drive the agent through /tui or session endpoints.
export OPENCODE_SERVER_USERNAME=ops
export OPENCODE_SERVER_PASSWORD="$(openssl rand -base64 32)"Tip: rotate the password per machine, store it in your OS keychain, refuse to start serve if the env var is empty.
Workspace Isolation and External-Directory Guard
opencode auto-loads opencode.json and .opencode/ from whichever directory you launch in — untrusted repos can ship hostile MCP commands, plugins, or agent files. external_directory defaults to "ask"; keep it that way.
{
"permission": {
"external_directory": {
"*": "ask",
"~/projects/trusted/**": "allow"
}
}
}Tip: run untrusted repos inside a container or VM, disable project-level plugin/MCP loading until you've reviewed opencode.json and .opencode/.
Tool Allowlist via permission
opencode's 13 built-in tools (bash, edit, write, webfetch, task, etc.) default to "allow". Tighten with pattern rules — last-match wins, so put * first.
{
"permission": {
"bash": { "*": "ask", "git status": "allow", "rm *": "deny", "curl *": "deny" },
"edit": { "*": "ask", "node_modules/**": "deny" },
"webfetch": "ask",
"task": "ask"
}
}Tip: never invoke headless opencode run -p ... against an untrusted prompt — -p auto-approves every permission. Use "ask" policies in interactive sessions and a deny-by-default policy under CI.
Credentials Hygiene — auth.json and .env
Provider keys from opencode auth login land in ~/.local/share/opencode/auth.json (plain JSON, no encryption documented), and OAuth tokens for MCP land in ~/.local/share/opencode/mcp-auth.json. opencode also auto-loads .env from the project root.
{
"permission": {
"read": { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow" }
}
}Tip: chmod 600 ~/.local/share/opencode/auth.json, prefer {env:ANTHROPIC_API_KEY} substitution over baking keys into config, never commit opencode.json containing inline keys.
Lock Down MCP Servers
MCP local servers run an arbitrary command array at startup with no prompt and no confirmation — a malicious opencode.json is straight-line code execution.
{
"mcp": {
"github": {
"type": "remote",
"url": "https://mcp.github.com",
"headers": { "Authorization": "Bearer {env:GH_MCP_TOKEN}" },
"enabled": true
},
"filesystem": { "type": "local", "command": ["npx","-y","@org/[email protected]"], "enabled": false }
}
}Tip: review every MCP entry on git pull, keep the count small, remember plugin tool.execute.before hooks do not intercept subagent calls (issue #5894).
Constrain Subagents and Custom Agents
Agents are markdown files in .opencode/agents/*.md with YAML frontmatter that can override global permissions. A repo-supplied subagent can quietly re-enable bash or edit.
---
description: Read-only code reviewer
mode: subagent
permission:
edit: deny
write: deny
bash: deny
webfetch: deny
task: deny
---Tip: treat .opencode/agents/ and .opencode/commands/ as code — review in PRs; prefer global agents in ~/.config/opencode/agents/ over project ones for sensitive roles.
Plugin Safety
Plugins in .opencode/plugins/ (and the global equivalent) are JS/TS modules auto-loaded at startup, with npm deps cached in ~/.cache/opencode/node_modules/. They have full Node privileges. A project that ships a plugin owns your shell.
ls -la .opencode/plugins/ ~/.config/opencode/plugins/Tip: disable plugin auto-load for unfamiliar repos (move/rename the directory before first launch), pin plugin versions, audit tool.execute.before hooks — they're bypassed by subagents, so layer them behind permission rules.
Prompt-Injection and Output-Rendering Defense
CVE-2026-22813 XSS shows model output is dangerous: pasted web content, MCP tool responses, and remote files can carry injected instructions or HTML. Use webfetch/websearch sparingly with "ask", set doom_loop: "ask" so repeated identical tool calls pause.
{
"permission": {
"webfetch": "ask",
"websearch": "ask",
"doom_loop": "ask"
}
}Tip: never paste raw issue/email/web text into a --prompt invocation with auto-approve; route untrusted inputs through a read-only subagent whose tool surface is denied by default.