All vulnerabilities
GHSA-cghp-86c6-6fjc

wheels-cli: Wheels CLI: shell injection in deploy, and path traversal and code injection in packages and generators

wheels-cli
CVSS
7.8High
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed in4.1.2Fixed versionGitHub
Published1 Oct 2026Updated 11 Oct 2026GitHub

What fixes it

A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.

Description

Impact

Several Wheels CLI commands use caller-supplied values without validating or escaping them. A value can come from a CI variable, a branch name, or an AI agent driving the CLI's MCP tools.

  1. Shell injection on deploy hosts (high). wheels deploy interpolates the --release/--version value and the rollback argument into remote shell commands, container names and image tags without escaping. A value such as feat$(cmd), which is a valid git ref name, runs commands on every deploy host as the SSH user, and on the CI runner during the build step.
  2. **Recursive deletion through packages remove (high).** The package name is not validated, so wheels packages remove .. deletes the project's contents. The command is exposed as an MCP tool and does not ask for confirmation.
  3. Package extraction is not contained (medium). A package archive is extracted into the whole vendor/ directory, so a malicious or compromised package can plant or overwrite files in vendor/wheels or other packages.
  4. Generator path traversal (medium). wheels generate controller|view|scaffold|… accepts names containing ../, and writes .cfm files outside the project. The command is exposed via MCP.
  5. **Deletion outside the project through wheels destroy (medium).** destroy deleted generated files without a containment check, so a symlinked model or view path made it delete files outside the project.
  6. Code injection into generated source (medium). Property, model, action, helper-function, migration and app names are interpolated into generated CFML without validation, so #…# expressions or quotes in a name become executable code at migrate or request time. The command is exposed via MCP.
  1. Stored XSS in generated scaffold views (medium). Since 4.1.0, the show view generated by wheels generate scaffold outputs the model's display property without HTML encoding. Any user who can create or edit a record can run script in the browser of anyone who views it. The generate admin views had the same unencoded output. Existing scaffolded apps need a one-line edit (see the release notes).
  1. RustCFML server commands trust a stale process ID (medium). wheels start|stop|status --engine=rustcfml used the process ID recorded in the server state file without checking that the process belongs to this project. After a crash leaves the state file behind, the operating system can reuse that ID for an unrelated process, which wheels stop would then terminate.

Patches

Fixed in 4.1.2. Names and versions are validated strictly, every interpolated value is shell-escaped, every file write and delete is contained to its canonical directory, and packages are extracted into an isolated staging directory before being moved into place.

Workarounds

Don't pass untrusted values (e.g. branch names) to wheels deploy --release, --version or rollback. Don't expose the Wheels MCP server to agents that handle untrusted content. Review package names and generator arguments before running them.

Affected: every release from 4.0.0 through 4.1.1.

Text from GitHub Advisory Database

Affected versions 1

  • wheels-cli, other>= 4.0.0, <= 4.1.1GitHub