83

There is the following code:

class Product < ActiveRecord::Base
  validates :title, :description, :image_url, presence: true
  validates :price, numericality: {greater_than_or_equal_to: 0.01}
  validates :title, uniqueness: true
  validates :image_url, allow_blank: true, format: {
      with: %r{\.(gif|jpg|png)$}i,
      message: 'URL must point to GIT/JPG/PNG pictures'
  }
end

It works, but when I try to test it using "rake test" I'll catch this message:

rake aborted!
The provided regular expression is using multiline anchors (^ or $), which may present a security risk. Did you mean to use \A and \z, or forgot to add the :multiline => true option?

What does it mean? How can I fix it?

Rajesh Omanakuttan
  • 6,788
  • 7
  • 47
  • 85
malcoauri
  • 11,904
  • 28
  • 82
  • 137

5 Answers5

158

^ and $ are Start of Line and End of Line anchors. While \A and \z are Permanent Start of String and End of String anchors.
See the difference:

string = "abcde\nzzzz"
# => "abcde\nzzzz"

/^abcde$/ === string
# => true

/\Aabcde\z/ === string
# => false

So Rails is telling you, "Are you sure you want to use ^ and $? Don't you want to use \A and \z instead?"

There is more on the rails security concern that generates this warning here.

oldergod
  • 15,033
  • 7
  • 62
  • 88
  • 3
    fixing up the unnecessary coloquialism – xaxxon Jul 23 '13 at 02:53
  • 2
    explains what it is asking but doesn't answer how to fix it. I suppose if you want to use ^ and $ the way to fix it is to add :multiline => true at the top of the class? – isimmons Sep 24 '13 at 03:46
  • @isimmons By adding `:multiline => true` you only fix the warning saying Rails you know what you are doing. – oldergod Sep 24 '13 at 23:57
  • 6
    The answer is there: it is to use \A and \z rather than ^ and $ because in Ruby, ^ and $ match only a newline not start and end of string, which allows a javascript exploit to pass the test. – JohnMerlino Aug 15 '14 at 16:28
31

This warning raises because your validation rule is vulnerable for javascript injection.

In your case \.(gif|jpg|png)$ matches till the end of the line. So your rule will validate this value pic.png\nalert(1); as true:

"test.png\n<script>alert(1)</script>" === /\.(gif|jpg|png)$/i
# => true

"test.png\n<script>alert(1)</script>" === /\.(gif|jpg|png)\z/i
# => false

Read the acticles:

ole
  • 5,166
  • 5
  • 29
  • 57
2

The problem regexp is not in devise, but rather lives in config/initializers/devise.rb. Change:

# Regex to use to validate the email address
config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i

to:

# Regex to use to validate the email address
  config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\Z/i
mcr
  • 4,615
  • 2
  • 31
  • 30
1

The warning is telling you that strings like the following will pass validation, but it is probably not what you want:

test = "image.gif\nthis is not an image"
re = /\.(gif|jpg|png)$/i
re.match(test) #=> #<MatchData ".gif" 1:"gif">

Both ^ and $ matches the start/end of any line, not the start/end of the string. \A and \z matches the start and the end of the full string, respectively.

re = /\.(gif|jpg|png)\z/i
re.match(test) #=> nil

The second part of the warning (“or forgot to add the :multiline => true option”) is telling you that if you actually want the behaviour of ^ and $ you can simply silence the warning passing the :multiline option.

yonosoytu
  • 3,319
  • 1
  • 17
  • 23
-1

If Ruby wants to see \z instead of the $ symbol sign, for security, you need to give it to him, then the code would look like this :

validates :image_url, allow_blank: true, format: {with: %r{\.(gif|jpg|png)\z}i, message: 'URL must point to GIF, JPG, PNG.'}
RamenChef
  • 5,557
  • 11
  • 31
  • 43
max
  • 1