Skip to content

[MEDIUM] Prevent shell injection through environment interpolation - #583

Open
OskarEichler wants to merge 1 commit into
capistrano:masterfrom
OskarEichler:codex/security-environment-interpolation
Open

[MEDIUM] Prevent shell injection through environment interpolation#583
OskarEichler wants to merge 1 commit into
capistrano:masterfrom
OskarEichler:codex/security-environment-interpolation

Conversation

@OskarEichler

Copy link
Copy Markdown

Summary

  • Reject environment keys that cannot be shell variable names.
  • Preserve documented $VAR and ${VAR} expansion in environment values.
  • Escape command substitution and backticks before interpolating values into the shell command.

Security impact

Command#environment_string currently places keys directly into an export statement and places values inside double quotes. A caller that passes attacker-influenced environment data can therefore execute commands through a crafted key, $(), or backticks. The command runs through both the Local shell backend and Net::SSH's remote exec path.

This is rated medium urgency: successful exploitation executes commands with the deployment user's privileges, but it requires an application or deployment integration to pass attacker-controlled keys or values into SSHKit's environment map.

Reproduction

A bounded external model passed three environment payloads to SSHKit::Command.new(:true, env: ...) and executed the resulting command locally:

dollar_paren command substitution executed;
backticks command substitution executed;
environment key injected a command

All three markers are created on v1.25.1 and current master (28e04dc). None are created with this patch.

Compatibility

The escaping deliberately retains the documented $PATH behavior and plain ${PATH} references. Focused execution also verifies spaces, quotes, escaped dollars, and ordinary backslashes keep their values.

Valid environment keys retain their current behavior. Invalid keys now raise ArgumentError; those keys could not form valid shell assignments. Command substitution in values is now passed literally rather than evaluated.

Verification

  • External injection/compatibility model: baseline fails all three injection cases; patched source passes on Ruby 4.0.6 and Ruby 3.2.11.
  • Existing Ruby 4.0.6 unit suite: 218 tests, 3,411 assertions, zero failures/errors/skips.
  • Existing Ruby 3.2.11 command tests: 40 tests, 63 assertions, zero failures/errors/skips.
  • Ruby syntax checks pass on both versions.
  • rake build produces sshkit-1.25.1.gem successfully.
  • git diff --check passes.

The Docker-backed remote functional suite was not run, and no real deployment or remote host was used. No test files, dependency metadata, or version files are changed.

Breaking changes

No change for valid environment names or ordinary values. Integrations intentionally relying on command substitution inside environment values must move that shell logic into an explicit command.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant