T09 · Insecure Skill Coding Practices
- Location
scripts/update_docker_run_container.py:109- Finding
Arbitrary Host Command Execution Through an Unvalidated Recreate Command
- Content
View full analysis
Vulnerability Details
File Location:
scripts/update_docker_run_container.py, lines 35–38 and 109–112
Vulnerability Type: OS command injection caused by unsafe shell execution
Risk Level: HighVulnerable Code
python def validate_recreate_command(recreate_command: str) -> None: stripped = recreate_command.strip() if not stripped.startswith("docker run"): raise ValueError("recreate_command must start with 'docker run'")python def recreate(recreate_command: str) -> None: proc = subprocess.run(recreate_command, shell=True, executable="/bin/bash", text=True) if proc.returncode != 0: raise CommandError("recreate_command execution failed")The vulnerable function is reached in apply mode at lines 154–157:
python if needs_update and args.apply: stop_and_remove(args.container_name) recreate(args.recreate_command) recreated = TrueTechnical Analysis
The script accepts
recreate_commandfrom a command-line argument and eventually passes the complete value to Bash withshell=True. The only direct validation is a textual check that the stripped value starts withdocker run.This prefix check does not establish that the input contains only one Docker invocation. Shell metacharacters and constructs—including command separators, pipelines, redirections, command substitutions, and additional commands—remain available to the caller. Although
extract_image()usesshlex.split()to identify an image, the resulting tokens are not used for execution and therefore do not mitigate injection.A crafted value can start with a syntactically valid Docker command, pass validation and image extraction, and then append another host command. Bash interprets that additional content when
recreate()is called.The workflow amplifies the operational risk because it stops and removes the existing container before executing the untrusted shell string. If the Docker invocation or injected su ...[truncated 1617 chars]
- Remediation
View remediation
Remediation Suggestions
-
Do not execute the recreate command through a shell. Parse the command into an argument vector and invoke Docker directly:
python tokens = shlex.split(recreate_command, posix=True) subprocess.run(tokens, shell=False, check=True, text=True) -
Validate the complete token vector. Require the first two tokens to be exactly
dockerandrun, confirm that an image exists, and reject unsupported or ambiguous syntax. Do not rely on a string-prefix check. -
Reject shell-specific constructs. If the interface must continue accepting a command string, reject separators, pipelines, redirections, substitutions, and other syntax that requires shell interpretation. Prefer accepting structured arguments rather than attempting to sanitize shell text.
-
Use one parser for validation and execution. Execute the exact token array that was validated and used to extract the image. Do not validate one interpretation and later execute the original string under Bash.
-
Verify container identity. Parse the
--nameoption and require it to match--container-name, preventing replacement commands from targeting an unintended logical container. -
Reduce service-loss risk. Fully validate the replacement invocation before stopping the existing container. Consider creating and verifying a replacement under a temporary name before removing the old container, where Docker naming and resource constraints permit it.
-
Implement failure recovery. If recreation fails after removal, provide a tested rollback mechanism or preserve sufficient trusted state to restore the prior container safely.
-
Add adversarial tests. Cover command separators, command substitutions, pipelines, redirections, multiline input, malformed quoting, unsupported Docker options, mismatched container names, and failed recreation after removal.
-
