ruvnet/ruflo · error

Invalid command: contains shell metacharacters

Error message

Invalid command: contains shell metacharacters

What it means

Validator.execCommand() — used to run the testCommand and buildCommand options of validate() — rejects any command containing ; & | ` $ ( ) < > before executing it with execSync. Chained commands, pipes, and substitutions are blocked rather than quoted.

Source

Thrown at v3/@claude-flow/deployment/src/validator.ts:275

  }

  /**
   * Allowed commands for security validation
   */
  private static readonly ALLOWED_COMMAND_PREFIXES = [
    'npm run ',
    'npm ',
    'npx ',
    'git ',
  ];

  /**
   * Execute command safely with validation
   */
  private execCommand(cmd: string, returnOutput = false): string {
    // Validate: check for shell metacharacters
    if (/[;&|`$()<>]/.test(cmd)) {
      throw new Error(`Invalid command: contains shell metacharacters`);
    }

    // Validate: must start with allowed prefix
    const isAllowed = Validator.ALLOWED_COMMAND_PREFIXES.some(
      prefix => cmd.startsWith(prefix)
    );
    if (!isAllowed) {
      throw new Error(`Command not allowed: ${cmd.split(' ')[0]}`);
    }

    try {
      const output = execSync(cmd, {
        cwd: this.cwd,
        encoding: 'utf-8',
        stdio: returnOutput ? 'pipe' : 'inherit',
        timeout: 60000, // 60 second timeout for builds
        maxBuffer: 50 * 1024 * 1024, // 50MB buffer for build output
      });

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Point testCommand/buildCommand at single package.json scripts: 'npm test', 'npm run build'
  2. Move any chaining inside the script definition itself, not into the command string passed to validate()

Example fix

// before
validate({ testCommand: 'npm run lint && npm test' }); // throws

// after
// package.json: "verify": "npm run lint && npm test"
validate({ testCommand: 'npm run verify' });
Defensive patterns

Strategy: validation

Validate before calling

function isValidatorSafeCommand(cmd: string): boolean {
  return !/[;&|`$()<>]/.test(cmd) && ['npm run ', 'npm ', 'npx ', 'git '].some(p => cmd.startsWith(p));
}
if (!isValidatorSafeCommand(testCommand)) throw new Error('use a single npm script for testCommand');
await validate({ testCommand, buildCommand });

Prevention

When it happens

Trigger: validate({ testCommand: 'npm test && npm run lint' }); buildCommand: 'npm run build 2>&1'; any option string containing &&, |, $( ), or redirection.

Common situations: Copying a combined lint+test line from CI config into ValidationOptions; build commands with subshells or output redirects.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/bd4bbfbaf62312c3. Report an issue: GitHub.