T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/orchestrator.py:42
- Finding
- Argument Injection Through Unsafe Saved-Output Substitution## Vulnerability Details **File Location**: `scripts/orchestrator.py`, lines 42–57 and 128–163 **Vulnerability Type**: Argument injection caused by unsafe string interpolation **Risk Level**: High ### Vulnerable Code ```python def substitute_vars(text, variables): """Replace {var_name} placeholders with actual values. SECURITY: {env.*} access is BLOCKED to prevent environment variable leakage. Only workflow-defined variables are substituted. """ def replacer(match): key = match.group(1) if key.startswith("env."): # BLOCKED: env var access via workflow variables is a credential leak vector return "{" + key + "}" value = variables.get(key) if value is None: return match.group(0) return str(value) return re.sub(r'\{(\w[\w.]*)\}', replacer, text) ``` ```python def run_step(step, variables, dry_run=False): """Execute a single workflow step.""" name = step.get("name", "unnamed") command = substitute_vars(step.get("command", ""), variables) on_fail = step.get("on_fail", "abort") condition = step.get("condition") save_output = step.get("save_output") timeout = step.get("timeout", 60) max_retries = 3 if on_fail == "retry" else 1 # Check condition if condition and not check_condition(condition, variables): print(f" SKIP [{name}] — condition not met: {condition}") return True, None # Validate command after substitution valid, reason = _validate_command(command) if not valid: print(f" BLOCKED [{name}] {reason}") return False, None if dry_run: print(f" [DRY] [{name}] {command}") return True, None for attempt in range(max_retries): if attempt > 0: print(f" RETRY [{name}] attempt {attempt + 1}/{max_retries}") time.sleep(2) pr ...[truncated 2771 chars]
- Remediation
- ## Remediation Suggestions - Define commands as arrays of arguments rather than shell-like strings, for example `["program", "--input", "{result}"]`. - Perform substitution independently within each array element so one substituted value cannot create additional arguments. - Treat all saved command output as untrusted. - Require structured output, such as validated JSON, and expose only explicitly selected fields to subsequent steps. - Apply per-variable schemas, length limits, and allowlists for expected formats such as paths, identifiers, or enumeration values. - Where a value may begin with `-`, use the target application's end-of-options marker (`--`) when supported. - Add tests covering whitespace, quotation marks, leading option prefixes, embedded newlines, and multi-argument payloads.
