Skip to content

Conversation

@kieranklaassen
Copy link

@kieranklaassen kieranklaassen commented Dec 9, 2025

Summary

Implements secure shell command execution from server to client as requested in #8.

  • Uses array-based execution (no shell interpretation) to prevent command injection attacks
  • Commands must be explicitly permitted by prefix (e.g. git status, bundle exec)
  • Working directory (chdir) validated against path entitlements
  • Timeout limits (default 30s, max 300s) prevent resource exhaustion
  • Output size limits (10MB) prevent memory exhaustion

User Configuration

Users can configure permissions via a config file at ~/.terminalwire/authorities/{authority}/config.yml:

# Example: ~/.terminalwire/authorities/localhost:3000/config.yml
shell:
  allow:
    - "git remote"
    - "git branch"
    - "git status"
    - "bundle exec"

paths:
  allow:
    - "~/.config/myapp"

environment_variables:
  allow:
    - "HOME"
    - "USER"

This allows users to grant permissions to specific servers without modifying code.

Server API

# Execute commands from server
result = context.shell.run("git", "status")
result = context.shell.run("bundle", "exec", "rspec", "--fail-fast")
result = context.shell.run("pwd", chdir: "/app", timeout: 60)

# Result object
result.stdout      # => "output string"
result.stderr      # => "error string"  
result.exitstatus  # => 0
result.success?    # => true

Security Design

  1. Array-based execution - Uses Open3.capture3(cmd, *args) which bypasses the shell entirely. Shell metacharacters like &&, ;, |, backticks are treated as literal strings.

  2. Command prefix allowlist - Commands are permitted by prefix matching (e.g. "git status" allows git status --short but not git push). No glob patterns to avoid bypass vulnerabilities.

  3. Path entitlement for chdir - If chdir is specified, it must be a permitted path.

  4. Resource limits - Timeout (max 300s) and output size (max 10MB) prevent exhaustion attacks.

  5. User-controlled permissions - All permissions are configured by the user, not the server. The server can only use what the user has explicitly allowed.

Test Plan

  • 18 integration tests covering:
    • Basic command execution (stdout, stderr, exit status)
    • Multiple arguments
    • Working directory (chdir)
    • Timeout handling
    • Shell injection prevention (metacharacters treated as literals)
    • Unauthorized command denial
    • Unauthorized chdir denial
  • All 66 integration tests pass

Closes #8

🤖 Generated with Claude Code

kieranklaassen and others added 3 commits December 9, 2025 09:40
Implements secure shell command execution from server to client as
requested in terminalwire#8. Uses array-based execution (no shell interpretation)
to prevent command injection attacks.

Security features:
- Commands must be explicitly permitted by prefix (e.g. "git status")
- Array execution via Open3.capture3 prevents shell injection
- Working directory (chdir) validated against path entitlements
- Timeout limits (default 30s, max 300s) prevent resource exhaustion
- Output size limits (10MB) prevent memory exhaustion

API:
  result = context.shell.run("git", "status")
  result = context.shell.run("bundle", "exec", "rspec", timeout: 60)
  result.stdout     # => "output"
  result.stderr     # => "errors"
  result.exitstatus # => 0
  result.success?   # => true

Closes terminalwire#8

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Users can now configure shell, path, and environment variable permissions
via a config file at ~/.terminalwire/authorities/{authority}/config.yml

Example config:
```yaml
shell:
  allow:
    - "git remote"
    - "git branch"
paths:
  allow:
    - "~/.config/myapp"
environment_variables:
  allow:
    - "HOME"
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Use catch/throw instead of direct exit() to allow Async cleanup
- Return exit status from connect() instead of calling exit inside
- Suppress async cleanup errors during shutdown

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.

Feature Request: Shell command execution on client

1 participant