T09 · Insecure Skill Coding Practices
- Location
release.py:9- Finding
Arbitrary Command Execution Through Unsanitized Release Version
- Content
View full analysis
None: """Run shell command""" print(f"→ {cmd}") result = subprocess.run(cmd, shell=True, check=check) if result.returncode != 0: sys.exit(result.returncode) def cmd_release(args) -> None: """Create a new release""" version = args.version print(f"Creating release {version}...") # Stage run("git add .") # Commit run(f'git commit -m "release: {version}"') # Tag run(f'git tag -a {version} -m "Version {version}"') # Push run("git push") run(f"git push origin {version}") ``` ### Technical Analysis The `run` function executes command strings through the operating-system shell. The `version` argument is supplied by the CLI user and is interpolated directly into three command strings without validation or shell-safe quoting. An attacker can include shell metacharacters or quote delimiters in the version value. These characters can terminate the intended Git argument and introduce an additional shell command. The vulnerability affects the commit, tag, and tag-push operations. The use of double quotes around some interpolations does not prevent exploitation because an input containing a double quote can terminate the quoted section. The final `git push origin` command interpolates the value without any quoting at all. ### Attack Path 1. An attacker gains the ability to influence the version passed to the release command. This may occur through direct CLI access, a wrapper script, or automated release input. 2. The attacker supplies a crafted value containing shell syntax, for example: ```bash gh-release release 'v1.0.0"; id; #' ``` 3. `cmd_release` inserts that value into a command such as: ```bash ...[truncated 1142 chars]- Remediation
View remediation
None: print("→", " ".join(cmd)) result = subprocess.run(cmd, shell=False, check=check) if result.returncode != 0: sys.exit(result.returncode) ``` 2. Invoke Git without constructing shell command strings: ```python run(["git", "commit", "-m", f"release: {version}"]) run(["git", "tag", "-a", version, "-m", f"Version {version}"]) run(["git", "push"]) run(["git", "push", "origin", version]) ``` 3. Validate the version against an explicit supported format before using it. For example, require a Semantic Versioning tag beginning with `v` and reject whitespace, control characters, shell metacharacters, and option-like values. 4. Insert `--` where supported to prevent a version beginning with `-` from being interpreted as a Git option. 5. Add automated tests covering quote characters, command separators, substitutions, newlines, leading hyphens, and malformed Semantic Versioning values. 6. Run release automation with a minimally privileged account and narrowly scoped repository credentials to reduce the impact of future command-execution defects. ]]>
