Vulnerability: lib/sup/message_chunks.rb in Sup before 0.13.2.1 and 0.14.x before 0.14.1.1 allows remote attackers to execute arbitrary commands via shell metacharacters in the content_type of an email attachment.
Vulnerability ID: CVE-2013-4479
CWE: CWE-94
Severity score: 6.4
Project: https://github.com/sup-heliotrope/sup
Published: 2013-12-07
File: lib/sup/message_chunks.rb
Commit message: security: prevent remote command injection in content_type
Commit author: Gaute Hope

Vulnerable version (before fix):
 class Attachment      def initialize content_type, filename, encoded_content, sibling_types       @content_type = content_type.downcase       @filename = filename       @quotable = false # changed to true if we can parse it through the                         # mime-decode hook, or if it's plain text def initialize content_type, filename, encoded_content, sibling_types       else         ## please see note in write_to_disk on important usage         ## of quotes to avoid remote command injection.         HookManager.run "mime-decode", :content_type => content_type,                         :filename => lambda { write_to_disk },                         :charset => encoded_content.charset,                         :sibling_types => sibling_types def view!     ## note that the path returned from write_to_disk is     ## Shellwords.escaped and is intended to be used without single     ## or double quotes. the use of either opens sup up for remote     ## code injection in the file name.     def write_to_disk       begin         file = Tempfile.new(["sup", Shellwords.escape(@filename.gsub("/", "_")) || "sup-attachment"])

Fixed version (after fix):
 class Attachment      def initialize content_type, filename, encoded_content, sibling_types       @content_type = content_type.downcase       if Shellwords.escape(@content_type) != @content_type         warn "content_type #{@content_type} is not safe, changed to application/octet-stream"         @content_type = 'application/octet-stream'       end        @filename = filename       @quotable = false # changed to true if we can parse it through the                         # mime-decode hook, or if it's plain text def initialize content_type, filename, encoded_content, sibling_types       else         ## please see note in write_to_disk on important usage         ## of quotes to avoid remote command injection.         HookManager.run "mime-decode", :content_type => @content_type,                         :filename => lambda { write_to_disk },                         :charset => encoded_content.charset,                         :sibling_types => sibling_types def view!     ## note that the path returned from write_to_disk is     ## Shellwords.escaped and is intended to be used without single     ## or double quotes. the use of either opens sup up for remote     ## code injection through the file name.     def write_to_disk       begin         file = Tempfile.new(["sup", Shellwords.escape(@filename.gsub("/", "_")) || "sup-attachment"])

Patch:
patch: @@ -113,6 +113,11 @@ class Attachment
 
     def initialize content_type, filename, encoded_content, sibling_types
       @content_type = content_type.downcase
+      if Shellwords.escape(@content_type) != @content_type
+        warn "content_type #{@content_type} is not safe, changed to application/octet-stream"
+        @content_type = 'application/octet-stream'
+      end
+
       @filename = filename
       @quotable = false # changed to true if we can parse it through the
                         # mime-decode hook, or if it's plain text
@@ -129,7 +134,7 @@ def initialize content_type, filename, encoded_content, sibling_types
       else
         ## please see note in write_to_disk on important usage
         ## of quotes to avoid remote command injection.
-        HookManager.run "mime-decode", :content_type => content_type,
+        HookManager.run "mime-decode", :content_type => @content_type,
                         :filename => lambda { write_to_disk },
                         :charset => encoded_content.charset,
                         :sibling_types => sibling_types
@@ -189,7 +194,7 @@ def view!
     ## note that the path returned from write_to_disk is
     ## Shellwords.escaped and is intended to be used without single
     ## or double quotes. the use of either opens sup up for remote
-    ## code injection in the file name.
+    ## code injection through the file name.
     def write_to_disk
       begin
         file = Tempfile.new(["sup", Shellwords.escape(@filename.gsub("/", "_")) || "sup-attachment"])
path: lib/sup/message_chunks.rb