Skip to content

security: [HIGH] Command injection in detectAgent/detectCloud functions in link.ts #3151

@louisgv

Description

@louisgv

File: packages/cli/src/commands/link.ts
Lines: 78-115
Severity: HIGH

Finding:
The detectAgent and detectCloud functions construct shell commands by directly concatenating values from the KNOWN_AGENTS array without proper escaping. While the current agent names are safe, this pattern creates a future maintenance hazard if agent names are ever modified or dynamically loaded.

Lines 81-82:

const psCmd =
  "ps aux 2>/dev/null | grep -oE 'claude(-code)?|openclaw|codex|opencode|kilocode|hermes|junie' | grep -v grep | head -1 || true";

Line 91:

const whichCmd = KNOWN_AGENTS.map((b) => `(which ${b} 2>/dev/null && echo ${b})`).join(" || ");

The whichCmd construction uses template literals with agent names directly embedded in shell commands. If an agent name contained shell metacharacters (e.g., agent$(whoami), agent;rm -rf /), it would be executed.

Impact:

  • Currently LOW risk: Agent names are hardcoded as safe strings in the KNOWN_AGENTS array
  • Future HIGH risk: If agent names are ever loaded from manifest.json or user input, this becomes a command injection vulnerability
  • Violates defense-in-depth principles — shell injection should be prevented at the construction site, not relied on upstream validation

Recommendation:

  1. Use proper shell escaping for all agent names before embedding in commands:

    // Add shell escaping utility
    function shellEscape(arg: string): string {
      return "'" + arg.replace(/'/g, "'\\''" + "'";
    }
    
    const whichCmd = KNOWN_AGENTS.map((b) => `(which ${shellEscape(b)} 2>/dev/null && echo ${shellEscape(b)})`).join(" || ");
  2. Better: Use array-based execution with spawnSync instead of shell string concatenation:

    for (const agent of KNOWN_AGENTS) {
      const result = spawnSync('which', [agent], { encoding: 'utf8' });
      if (result.status === 0) return agent;
    }
  3. Add validation tests for shell metacharacters in agent names even though they're currently safe

Related:

  • Similar patterns exist in lines 106-112 for cloud detection (curl commands with hardcoded safe values)
  • defaultSshCommand on line 46 correctly uses array-based args to avoid injection

-- security/code-scanner

Metadata

Metadata

Assignees

No one assigned

    Labels

    safe-to-workSecurity triage: safe for automated processing

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions