Hi,

I've created a small class and supporting methods for sending email from a
web page. I use it like this:

    msg = Web::Email::Message.new(
     :from => from,
     :to => to,
     :subject => subject,
     :body => body.untaint # security vulnerability?
    )
    Web::Email.send(msg)

All of the email strings (:from, :to, etc...) could potentially come from
the the outside world. I'm doing some munging on the :from, :to, and
:subject strings replacing \n \r \f \e and \b with something
non-threatening. Right now I'm just untainting the :body string, but I have
the distinct feeling that I may be exposing myself to a security
vulnerability because I don't really understand what the Net::SMTP class is
doing in the background.

Could someone who understands how Net::SMTP works check over my code (see
below) and comment on security vulnerabilities? Also I looked for details on
specification for email, but a brief search on google didn't turn up
anything. Can someone point me in the right direction?

Thanks,

John Long
http://wiseheartdesign.com

<code>
# you will probably want to paste this into
# a syntax highlighting editor like Scite
require 'net/smtp'
module Web
 module Email
  class Message
   attr_accessor :from, :to, :subject, :body

   def initialize(hash = {})
    @from = hash[:from]
    @to = hash[:to]
    @subject = hash[:subject]
    @body = hash[:body]
   end

   def message
    time = current_time
    <<-SMTP_MSG
Subject: #{@subject}
Message-Id: <#{"%.8f" % time.to_f}@iblp.org>
Date: #{time.strftime("%a, %d %b %Y %H:%M:%S %z %Z")}
From: #{@from}
To: #{@to}

#{@body}
    SMTP_MSG
   end

   def current_time
    Time.now
   end
  end
  def self.send(msg)
   msg.subject = safe_subject(msg.subject) # munges and untaints string
   msg.from = safe_address(msg.from)
   msg.to = safe_address(msg.to)
   raise ArgumentError, 'msg.body tainted' if msg.body.tainted?
   raise ArgumentError, 'msg tainted' if msg.tainted?
   Net::SMTP.start('localhost', 25) {|smtp|
    smtp.sendmail(msg.message, msg.from, msg.to)
   }
  end
  def self.safe_subject(subject)
   subject.gsub(/[\n\r\f\e\b]/, ' ').untaint
  end
  def self.safe_address(address)
   address.gsub(/[\n\r\f\e\b]/, '').untaint
  end
 end
end
</code>