Skip to content

fix(security): Phase 1 — symlink bypass, command injection, server auth, sensitive files#26

Merged
e6qu merged 1 commit intodevfrom
phase1/security-fixes
Mar 21, 2026
Merged

fix(security): Phase 1 — symlink bypass, command injection, server auth, sensitive files#26
e6qu merged 1 commit intodevfrom
phase1/security-fixes

Conversation

@e6qu
Copy link
Copy Markdown
Owner

@e6qu e6qu commented Mar 21, 2026

Phase 1: Security Fixes

Fixes 4 of 5 security issues (S1, S2, S4, S5). S3 partially mitigated with warning log.

These fixes address vulnerabilities originally reported by upstream OpenCode community members. Full credit to the original reporters and PR authors below.

S1: Filesystem.contains() symlink bypass (CRITICAL) — FIXED

  • Added realpathSync() resolution before lexical path check in util/filesystem.ts
  • Symlinks pointing outside project directory now correctly rejected
  • Falls back to lexical check for non-existent files (write tool creates new files)

Original report: anomalyco/opencode#8313 by mluckydream
Related fix PR: anomalyco/opencode#14581 by Nicoo01x (cross-drive path bypass on Windows)
Also related: anomalyco/opencode#14579 by mluckydream (cross-drive bypass)
Also related: anomalyco/opencode#11703 (path traversal in file tools)

S2: exec() command injection (HIGH) — FIXED

  • Replaced exec(shellString) with spawn(cmd, [url]) in cli/cmd/github.ts
  • No shell interpolation possible — argument array prevents injection

Original report: anomalyco/opencode#17350 by kvenux
Related fix PR: anomalyco/opencode#17346 by kvenux (sanitize CLI command args)
Also related: anomalyco/opencode#6948 by RinZ27 (harden BashTool command parsing)

S4: Server auth on non-loopback (MED) — FIXED

  • Server.listen() throws if binding to non-loopback without OPENCODE_SERVER_PASSWORD
  • Loopback addresses (127.0.0.1, localhost, ::1) still work without password

Original report: anomalyco/opencode#10973
Also related: anomalyco/opencode#6355 by Mishkun (RCE via CORS + no auth)
CVE: CVE-2026-22812 (CVSS 8.8) reported by CyberShadow
Related fix PR: anomalyco/opencode#10974 by MaxMiksa (guard TUI server exposure)
Also related: anomalyco/opencode#14568 by judepereira (remove SERVER_PASSWORD from env after read)

S5: Read tool sensitive files (MED) — FIXED

  • Added deny-list: .env*, secrets.json, credentials.json, .netrc, *.pem, *.key, .aws/, .ssh/, .gnupg/, .kube/
  • Sensitive files use always: [] (forces permission prompt every time)
  • Non-sensitive files keep always: ["*"] (existing behavior preserved)

Original report: anomalyco/opencode#12196 by cupton-paa
Related fix PR: anomalyco/opencode#14108 by edevil (strip env var assignments from bash permissions)

S3: Workspace trust (HIGH) — PARTIALLY MITIGATED

  • Warning log when loading workspace .opencode/ config
  • Full trust prompt (VS Code model) planned for future PR

Original reports:

Test plan

  • bun run typecheck (tsgo) — 0 errors
  • bun test — 1486 pass, 0 fail (13 new security tests)
  • Symlink escape test: symlink outside project → contains() returns false
  • Sensitive file test: .env, .pem, .aws/credentials detected
  • Existing .env permission tests still pass (10 tests)

S1 (CRITICAL): Filesystem.contains() symlink bypass
- Added realpathSync() resolution before lexical path check
- Symlinks pointing outside project are now correctly rejected
- Falls back to lexical check for non-existent files (write tool)

S2 (HIGH): exec() command injection in github.ts
- Replaced exec(shellString) with spawn(cmd, args) argument array
- No shell interpolation possible

S4 (MED): Server unauthenticated on non-loopback
- Server.listen() throws if binding to non-loopback without
  OPENCODE_SERVER_PASSWORD set

S5 (MED): Read tool exposes sensitive files
- Added deny-list (SENSITIVE_PATTERNS + SENSITIVE_DIRS) for .env,
  credentials, keys, .aws, .ssh, etc.
- Sensitive files use always:[] (forces permission prompt every time)
- Non-sensitive files keep always:["*"] (existing behavior)

S3 (HIGH): Workspace trust — partial mitigation
- Added warning log when loading workspace .opencode/ config
- Full trust prompt (VS Code model) planned for future PR

13 security regression tests added (2 test files).
1486 tests passing, 0 tsgo errors.
@e6qu e6qu merged commit f63f0b1 into dev Mar 21, 2026
1 check passed
@e6qu e6qu deleted the phase1/security-fixes branch March 21, 2026 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant