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