An agent is able to read all filesystem outside a project directory in Plan mode
Description
I do not like that an agent is able to read all filesystem outside a project directory in Plan mode without asking for permission. I was surprised when I saw it first time.
OpenCode/LLM say that I can trust them, it is safe. As if! (c) Big Bro
So I investigated what was going on under the hood.
And I found following troubles:
| # | Severity | Issue | Location | Status |
|---|---|---|---|---|
| 1 | CRITICAL | WriteTool had NO external_directory check | write.ts:25-30 |
✅ Fixed |
| 2 | CRITICAL | Bash tool only checked write commands, not read commands (ls, cat, etc.) |
bash.ts:111 |
✅ Fixed |
| 3 | CRITICAL | Filesystem.contains() was lexical-only (symlinks could escape) |
filesystem.ts:25 |
✅ Fixed |
| 4 | HIGH | GrepTool - no path boundary check | grep.ts |
✅ Fixed |
| 5 | HIGH | GlobTool - no path boundary check | glob.ts |
✅ Fixed |
| 6 | HIGH | ListTool - no path boundary check | ls.ts |
✅ Fixed |
| 7 | HIGH | ReadTool - used sync contains() instead of containsSafe() |
read.ts:30 |
✅ Fixed |
| 8 | HIGH | EditTool - used sync contains() |
edit.ts:43 |
✅ Fixed |
| 9 | HIGH | PatchTool - used sync contains() |
patch.ts:53 |
✅ Fixed |
| 10 | HIGH | File.read() and File.list() - symlink bypass | file/index.ts |
✅ Fixed |
| 11 | HIGH | bypassCwdCheck flag could skip all checks |
read.ts:30 |
Documented |
| 12 | MEDIUM | Env.all() exposes all environment variables | env/index.ts |
Not fixed (optional) |
| 13 | MEDIUM | Plugin system - arbitrary code execution via config | plugin/index.ts |
Documented |
| 14 | MEDIUM | MCP server command injection via config | mcp/index.ts |
Documented |
I'm ok with bypassCwdCheck, but others do not make happy.
A containsSafe function resolves symlinks before checking if a path is inside the project directory.
I applied fixes above locally and I could not test it because bun dev and bun dev . commands failed constantly.
I had to go to packages/opencode and run a bun src/index.ts command.
Also I found that some tools may exit from Plan mode on their own without any confirmation.
I got what I expected in result, and then I found an ui bug.
A question is everything above is intended behavior?
I would like to know about possible following steps.
p.s.: I used Opus 4.5 and GLM 4.7 models, both provided almost similar results.
Plugins
Standard installation
OpenCode version
1.1.8
Steps to reproduce
send a prompt: list content of ../ dir
Screenshot and/or share link
No response
Operating System
macOS 15.7.3 (Intel)
Terminal
Terminal
This issue might be a duplicate of or closely related to existing security issues. Please check:
- #7498: Grep Tool Fails on Symlinks—handles symlink security which relates to path boundary issues mentioned in your investigation
- #7478: BashTool input validation security hardening - addresses bash command execution safety
- #7474: [Security Bug] Subagent permissions not enforced - similar critical security issue about permission bypasses
- #6527: [Security Issue/Bug] Plan mode restrictions bypassed when spawning sub-agents - demonstrates permission system bypass issues similar to those you identified
- #7173: Security Issue - Lifecycle Script Execution via .opencode/package.json - related RCE security issue
- #7163: Security Issue - Autoloading Repository Plugins - related automatic execution security issue
- #7279: Bug: permission pathing crossplatform - relates to path boundary checking on different platforms
Your investigation appears comprehensive and identifies multiple legitimate security concerns. The issues above share similar themes around boundary checking, permission enforcement, and symlink handling that your issue #7504 highlights.