CVE-2014-0156
Description
AwesomeSpawn Ruby gem had an OS command injection vulnerability allowing arbitrary command execution via unsanitized parameters.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
AwesomeSpawn Ruby gem had an OS command injection vulnerability allowing arbitrary command execution via unsanitized parameters.
Vulnerability
Overview
The awesome_spawn Ruby gem, which provides a wrapper around Kernel.spawn, contained an OS command injection vulnerability in its build_command_line method. The method failed to properly sanitize user-supplied parameters, allowing an attacker to inject arbitrary shell commands. The fix involved separating command line building and sanitizing into its own class, as seen in commit e524f85 [1].
Exploitation
An attacker could exploit this flaw by passing specially crafted parameters to commands executed via AwesomeSpawn.run. For example, passing {'-l' => ";touch haxored"} as parameters would result in the execution of the injected command after the intended ls -l command [4]. No authentication is required if the attacker controls the input passed to the gem.
Impact
Successful exploitation allows an attacker to execute arbitrary OS commands with the privileges of the Ruby process. This could lead to full system compromise, data exfiltration, or further lateral movement within the affected environment [2][4].
Mitigation
The vulnerability is patched in awesome_spawn versions >= 1.3.0 and ~> 1.2.0. Users are advised to upgrade to a patched version immediately. No workarounds are available [1][4].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
awesome_spawnRubyGems | < 1.2.0 | 1.2.0 |
Affected products
2- Awesome spawn/Awesome spawndescription
Patches
1e524f85f1c6eSeparate command line building and sanitizing into its own class.
4 files changed · +150 −117
lib/awesome_spawn/command_line_builder.rb+59 −0 added@@ -0,0 +1,59 @@ +require "shellwords" + +module AwesomeSpawn + class CommandLineBuilder + # Build the full command line. + # + # @param [String] command The command to run + # @param [Hash,Array] params Optional command line parameters. They can + # be passed as a Hash or associative Array. The values are sanitized to + # prevent command line injection. Keys as symbols are prefixed with `--`, + # and `_` is replaced with `-`. + # + # - `{:key => "value"}` generates `--key value` + # - `{"--key" => "value"}` generates `--key value` + # - `{:key= => "value"}` generates `--key=value` + # - `{"--key=" => "value"}` generates `--key=value` + # - `{:key_name => "value"}` generates `--key-name value` + # - `{:key => nil}` generates `--key` + # - `{"-f" => ["file1", "file2"]}` generates `-f file1 file2` + # - `{nil => ["file1", "file2"]}` generates `file1 file2` + # + # @return [String] The full command line + def build(command, params = nil) + return command.to_s if params.nil? || params.empty? + "#{command} #{assemble_params(sanitize(params))}" + end + + private + + def sanitize(params) + return [] if params.nil? || params.empty? + params.collect do |k, v| + [sanitize_key(k), sanitize_value(v)] + end + end + + def sanitize_key(key) + case key + when Symbol then "--#{key.to_s.tr("_", "-")}" + else key + end + end + + def sanitize_value(value) + case value + when Array then value.collect { |i| i.to_s.shellescape } + when NilClass then value + else value.to_s.shellescape + end + end + + def assemble_params(sanitized_params) + sanitized_params.collect do |pair| + pair_joiner = pair.first.to_s.end_with?("=") ? "" : " " + pair.flatten.compact.join(pair_joiner) + end.join(" ") + end + end +end
lib/awesome_spawn.rb+3 −50 modified@@ -1,9 +1,9 @@ require "awesome_spawn/version" +require "awesome_spawn/command_line_builder" require "awesome_spawn/command_result" require "awesome_spawn/command_result_error" require "awesome_spawn/no_such_file_error" -require "shellwords" require "open3" module AwesomeSpawn @@ -100,60 +100,13 @@ def run!(command, options = {}) command_result end - # Build the full command line. - # - # @param [String] command The command to run - # @param [Hash,Array] params Optional command line parameters. They can - # be passed as a Hash or associative Array. The values are sanitized to - # prevent command line injection. Keys as symbols are prefixed with `--`, - # and `_` is replaced with `-`. - # - # - `{:key => "value"}` generates `--key value` - # - `{"--key" => "value"}` generates `--key value` - # - `{:key= => "value"}` generates `--key=value` - # - `{"--key=" => "value"}` generates `--key=value` - # - `{:key_name => "value"}` generates `--key-name value` - # - `{:key => nil}` generates `--key` - # - `{"-f" => ["file1", "file2"]}` generates `-f file1 file2` - # - `{nil => ["file1", "file2"]}` generates `file1 file2` - # - # @return [String] The full command line + # (see CommandLineBuilder#build) def build_command_line(command, params = nil) - return command.to_s if params.nil? || params.empty? - "#{command} #{assemble_params(sanitize(params))}" + CommandLineBuilder.new.build(command, params) end private - def sanitize(params) - return [] if params.nil? || params.empty? - params.collect do |k, v| - [sanitize_key(k), sanitize_value(v)] - end - end - - def sanitize_key(key) - case key - when Symbol then "--#{key.to_s.tr("_", "-")}" - else key - end - end - - def sanitize_value(value) - case value - when Array then value.collect { |i| i.to_s.shellescape } - when NilClass then value - else value.to_s.shellescape - end - end - - def assemble_params(sanitized_params) - sanitized_params.collect do |pair| - pair_joiner = pair.first.to_s.end_with?("=") ? "" : " " - pair.flatten.compact.join(pair_joiner) - end.join(" ") - end - def launch(command, in_data, spawn_options = {}) spawn_options = spawn_options.merge(:stdin_data => in_data) if in_data output, error, status = Open3.capture3(command, spawn_options)
spec/awesome_spawn_spec.rb+0 −67 modified@@ -128,71 +128,4 @@ let(:run_method) {"run!"} end end - - context ".build_command_line" do - it "sanitizes crazy params" do - cl = subject.build_command_line("true", modified_params) - expect(cl).to eq "true --user bob --pass P@\\$sw0\\^\\&\\ \\|\\<\\>/-\\+\\*d\\% --db --desc=Some\\ Description --symkey --symkey-dash pkg1 some\\ pkg --pool 123 --pool 456" - end - - it "handles Symbol keys" do - cl = subject.build_command_line("true", :abc => "def") - expect(cl).to eq "true --abc def" - end - - it "handles Symbol keys with tailing '='" do - cl = subject.build_command_line("true", :abc= => "def") - expect(cl).to eq "true --abc=def" - end - - it "handles Symbol keys with underscore" do - cl = subject.build_command_line("true", :abc_def => "ghi") - expect(cl).to eq "true --abc-def ghi" - end - - it "handles Symbol keys with underscore and tailing '='" do - cl = subject.build_command_line("true", :abc_def= => "ghi") - expect(cl).to eq "true --abc-def=ghi" - end - - it "sanitizes Fixnum array param value" do - cl = subject.build_command_line("true", nil => [1]) - expect(cl).to eq "true 1" - end - - it "sanitizes Pathname param value" do - cl = subject.build_command_line("true", nil => [Pathname.new("/usr/bin/ruby")]) - expect(cl).to eq "true /usr/bin/ruby" - end - - it "sanitizes Pathname param key" do - cl = subject.build_command_line("true", Pathname.new("/usr/bin/ruby") => nil) - expect(cl).to eq "true /usr/bin/ruby" - end - - it "with params as empty Hash" do - cl = subject.build_command_line("true", {}) - expect(cl).to eq "true" - end - - it "with params as nil" do - cl = subject.build_command_line("true", nil) - expect(cl).to eq "true" - end - - it "without params" do - cl = subject.build_command_line("true") - expect(cl).to eq "true" - end - - it "with Pathname command" do - cl = subject.build_command_line(Pathname.new("/usr/bin/ruby")) - expect(cl).to eq "/usr/bin/ruby" - end - - it "with Pathname command and params" do - cl = subject.build_command_line(Pathname.new("/usr/bin/ruby"), "-v" => nil) - expect(cl).to eq "/usr/bin/ruby -v" - end - end end
spec/command_line_builder_spec.rb+88 −0 added@@ -0,0 +1,88 @@ +require 'spec_helper' + +describe AwesomeSpawn::CommandLineBuilder do + subject { described_class.new } + + let(:params) do + { + "--user" => "bob", + "--pass" => "P@$sw0^& |<>/-+*d%", + "--db" => nil, + "--desc=" => "Some Description", + :symkey => nil, + :symkey_dash => nil, + nil => ["pkg1", "some pkg"] + } + end + + let (:modified_params) do + params.to_a + [123, 456].collect {|pool| ["--pool", pool]} + end + + context "#build" do + it "sanitizes crazy params" do + cl = subject.build("true", modified_params) + expect(cl).to eq "true --user bob --pass P@\\$sw0\\^\\&\\ \\|\\<\\>/-\\+\\*d\\% --db --desc=Some\\ Description --symkey --symkey-dash pkg1 some\\ pkg --pool 123 --pool 456" + end + + it "handles Symbol keys" do + cl = subject.build("true", :abc => "def") + expect(cl).to eq "true --abc def" + end + + it "handles Symbol keys with tailing '='" do + cl = subject.build("true", :abc= => "def") + expect(cl).to eq "true --abc=def" + end + + it "handles Symbol keys with underscore" do + cl = subject.build("true", :abc_def => "ghi") + expect(cl).to eq "true --abc-def ghi" + end + + it "handles Symbol keys with underscore and tailing '='" do + cl = subject.build("true", :abc_def= => "ghi") + expect(cl).to eq "true --abc-def=ghi" + end + + it "sanitizes Fixnum array param value" do + cl = subject.build("true", nil => [1]) + expect(cl).to eq "true 1" + end + + it "sanitizes Pathname param value" do + cl = subject.build("true", nil => [Pathname.new("/usr/bin/ruby")]) + expect(cl).to eq "true /usr/bin/ruby" + end + + it "sanitizes Pathname param key" do + cl = subject.build("true", Pathname.new("/usr/bin/ruby") => nil) + expect(cl).to eq "true /usr/bin/ruby" + end + + it "with params as empty Hash" do + cl = subject.build("true", {}) + expect(cl).to eq "true" + end + + it "with params as nil" do + cl = subject.build("true", nil) + expect(cl).to eq "true" + end + + it "without params" do + cl = subject.build("true") + expect(cl).to eq "true" + end + + it "with Pathname command" do + cl = subject.build(Pathname.new("/usr/bin/ruby")) + expect(cl).to eq "/usr/bin/ruby" + end + + it "with Pathname command and params" do + cl = subject.build(Pathname.new("/usr/bin/ruby"), "-v" => nil) + expect(cl).to eq "/usr/bin/ruby -v" + end + end +end
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-qpqw-mc85-qvm9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2014-0156ghsaADVISORY
- github.com/ManageIQ/awesome_spawn/commit/e524f85f1c6e292ef7d117d7818521307ac269ffghsax_refsource_MISCWEB
- rubysec.com/advisories/CVE-2014-0156ghsaWEB
- rubysec.com/advisories/CVE-2014-0156/mitrex_refsource_MISC
News mentions
0No linked articles in our index yet.