T09 · Insecure Skill Coding Practices
- Location
scripts/orchestrator.py:167- Finding
Shell Command Injection Through Unescaped Upstream Output Substitution
- Content
View full analysis
Vulnerability Details
File Location:
scripts/orchestrator.py, lines 167–170
Vulnerability Type: Command injection
Risk Level: HighVulnerable Code
python cmd = n.get("run", "") for dep, val in outputs.items(): cmd = cmd.replace(f"{{{{{dep}}}}}", (val or "").strip()) print(f"▶ 运行 {k}: {cmd}") r = subprocess.run(cmd, shell=True, capture_output=True, text=True)Technical Analysis
Captured output from previously executed nodes is inserted verbatim into a downstream command string. The resulting string is then passed to
subprocess.runwithshell=True.Consequently, shell metacharacters and command substitutions contained in an upstream node's output are interpreted as shell syntax rather than treated as data. Examples of dangerous output include semicolon-separated commands, command substitutions, pipelines, redirects, and logical operators.
The documentation states that chain definitions should be trusted, but this does not eliminate the vulnerability. A trusted chain may process untrusted files, repository contents, API responses, user input, or other external data and print that data to stdout. If the stdout is subsequently referenced through a
{{node_id}}placeholder, an attacker who controls that data can cross the data-to-code boundary.Attack Path
- A chain contains an upstream node whose stdout is captured.
- The upstream node processes attacker-controlled data and prints a value containing shell syntax, such as
$(malicious-command)or; malicious-command. - A downstream node includes the upstream placeholder, such as
tool --value "{{upstream}}". - The orchestrator replaces the placeholder with the unescaped stdout.
- The orchestrator executes the assembled command with
shell=True. - The shell interprets the injected syntax and executes the attacker's command with the orchestrator process's privileges.
Impact Assessment
Successful exploita ...[truncated 577 chars]
- Remediation
View remediation
Remediation Suggestions
- Avoid constructing shell command strings from dynamic data.
- Define node commands as argument arrays and invoke them with
subprocess.run(arguments, shell=False). - Transfer upstream output through stdin, temporary data files with controlled permissions, or explicitly defined environment variables instead of interpolating it into executable syntax.
- If shell execution is an unavoidable compatibility requirement, apply platform-appropriate quoting such as
shlex.quoteto every substituted value. Treat this as defense in depth rather than the preferred design. - Add a chain schema that distinguishes static executable arguments from dynamic data arguments.
- Run workflows under a dedicated, least-privileged account or sandbox without unnecessary credentials, filesystem access, or network access.
- Add regression tests using outputs containing semicolons, command substitutions, redirects, pipes, quotes, newlines, and logical operators to verify that these values cannot trigger command execution.
