brakeman 2.1.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,12 @@
1
+ # 2.2.0
2
+
3
+ * Reduce command injection false positives
4
+ * Use Rails version from Gemfile if it is available
5
+ * Only add routes with actual names
6
+ * Ignore redirects to models using friendly_id (AJ Ostrow)
7
+ * Support scanning Rails engines (Geoffrey Hichborn)
8
+ * Add check for detailed exceptions in production
9
+
1
10
  # 2.1.2
2
11
 
3
12
  * Do not attempt to load custom Haml filters
data/README.md CHANGED
@@ -29,7 +29,7 @@ Using RubyGems:
29
29
 
30
30
  gem install brakeman
31
31
 
32
- Using Bundler, add to development group in Gemfile:
32
+ Using Bundler, add to development group in Gemfile and set to not be required automatically:
33
33
 
34
34
  group :development do
35
35
  gem 'brakeman', :require => false
@@ -163,4 +163,6 @@ The default config locations are `./config/brakeman.yml`, `~/.brakeman/config.ym
163
163
 
164
164
  The `-c` option can be used to specify a configuration file to use.
165
165
 
166
- # License see MIT-LICENSE
166
+ # License
167
+
168
+ see MIT-LICENSE
@@ -66,7 +66,7 @@ module Brakeman
66
66
  end
67
67
 
68
68
  def layout_exists?(name)
69
- pattern = "#{@root}/app/views/layouts/#{name}.html.{erb,haml,slim}"
69
+ pattern = "#{@root}/{engines/*/,}app/views/layouts/#{name}.html.{erb,haml,slim}"
70
70
  !Dir.glob(pattern).empty?
71
71
  end
72
72
 
@@ -77,7 +77,7 @@ module Brakeman
77
77
  private
78
78
 
79
79
  def find_paths(directory, extensions = "*.rb")
80
- pattern = @root + "/#{directory}/**/#{extensions}"
80
+ pattern = @root + "/{engines/*/,}#{directory}/**/#{extensions}"
81
81
 
82
82
  select_files(Dir.glob(pattern).sort)
83
83
  end
@@ -0,0 +1,54 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ # Check for detailed exceptions enabled for production
4
+ class Brakeman::CheckDetailedExceptions < Brakeman::BaseCheck
5
+ Brakeman::Checks.add self
6
+
7
+ LOCAL_REQUEST = s(:call, s(:call, nil, :request), :local?)
8
+
9
+ @description = "Checks for information disclosure displayed via detailed exceptions"
10
+
11
+ def run_check
12
+ check_local_request_config
13
+ check_detailed_exceptions
14
+ end
15
+
16
+ def check_local_request_config
17
+ if true? tracker.config[:rails][:consider_all_requests_local]
18
+ warn :warning_type => "Information Disclosure",
19
+ :warning_code => :local_request_config,
20
+ :message => "Detailed exceptions are enabled in production",
21
+ :confidence => CONFIDENCE[:high],
22
+ :file => "config/environments/production.rb"
23
+ end
24
+ end
25
+
26
+ def check_detailed_exceptions
27
+ tracker.controllers.each do |name, controller|
28
+ controller[:public].each do |name, method|
29
+ body = method.body.last
30
+ next unless body
31
+
32
+ if name == :show_detailed_exceptions? and not safe? body
33
+ if true? body
34
+ confidence = CONFIDENCE[:high]
35
+ else
36
+ confidence = CONFIDENCE[:med]
37
+ end
38
+
39
+ warn :warning_type => "Information Disclosure",
40
+ :warning_code => :detailed_exceptions,
41
+ :message => "Detailed exceptions may be enabled in 'show_detailed_exceptions?'",
42
+ :confidence => confidence,
43
+ :code => method,
44
+ :file => controller[:file]
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def safe? body
51
+ false? body or
52
+ body == LOCAL_REQUEST
53
+ end
54
+ end
@@ -13,6 +13,10 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
13
13
 
14
14
  @description = "Finds instances of possible command injection"
15
15
 
16
+ SAFE_VALUES = [s(:const, :RAILS_ROOT),
17
+ s(:call, s(:const, :Rails), :root),
18
+ s(:call, s(:const, :Rails), :env)]
19
+
16
20
  #Check models, controllers, and views for command injection.
17
21
  def run_check
18
22
  Brakeman.debug "Finding system calls using ``"
@@ -38,9 +42,9 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
38
42
 
39
43
  case call.method
40
44
  when :system, :exec
41
- failure = include_user_input?(first_arg) || include_interp?(first_arg)
45
+ failure = include_user_input?(first_arg) || dangerous_interp?(first_arg)
42
46
  else
43
- failure = include_user_input?(args) || include_interp?(args)
47
+ failure = include_user_input?(args) || dangerous_interp?(args)
44
48
  end
45
49
 
46
50
  if failure and not duplicate? result
@@ -82,9 +86,11 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
82
86
  if input = include_user_input?(exp)
83
87
  confidence = CONFIDENCE[:high]
84
88
  user_input = input.match
85
- else
89
+ elsif input = dangerous?(exp)
86
90
  confidence = CONFIDENCE[:med]
87
- user_input = nil
91
+ user_input = input
92
+ else
93
+ return
88
94
  end
89
95
 
90
96
  warn :result => result,
@@ -95,4 +101,39 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
95
101
  :user_input => user_input,
96
102
  :confidence => confidence
97
103
  end
104
+
105
+ def dangerous? exp
106
+ exp.each_sexp do |e|
107
+ next if node_type? e, :lit, :str
108
+ next if SAFE_VALUES.include? e
109
+
110
+ if call? e and e.method == :to_s
111
+ e = e.target
112
+ end
113
+
114
+ if node_type? e, :or, :evstr, :string_eval, :string_interp
115
+ if res = dangerous?(e)
116
+ return res
117
+ end
118
+ else
119
+ return e
120
+ end
121
+ end
122
+
123
+ false
124
+ end
125
+
126
+ def dangerous_interp? exp
127
+ match = include_interp? exp
128
+ return unless match
129
+ interp = match.match
130
+
131
+ interp.each_sexp do |e|
132
+ if res = dangerous?(e)
133
+ return Match.new(:interp, res)
134
+ end
135
+ end
136
+
137
+ false
138
+ end
98
139
  end
@@ -128,7 +128,7 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
128
128
  if node_type? exp, :or
129
129
  model_instance? exp.lhs or model_instance? exp.rhs
130
130
  elsif call? exp
131
- if model_name? exp.target and
131
+ if model_name? exp.target or friendly_model? exp.target and
132
132
  (@model_find_calls.include? exp.method or exp.method.to_s.match(/^find_by_/))
133
133
  true
134
134
  else
@@ -137,6 +137,12 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
137
137
  end
138
138
  end
139
139
 
140
+ #Returns true if exp is (probably) a friendly model instance
141
+ #using the FriendlyId gem
142
+ def friendly_model? exp
143
+ call? exp and model_name? exp.target and exp.method == :friendly
144
+ end
145
+
140
146
  #Returns true if exp is (probably) a decorated model instance
141
147
  #using the Draper gem
142
148
  def decorated_model? exp
@@ -19,6 +19,11 @@ class Brakeman::GemProcessor < Brakeman::BaseProcessor
19
19
  @tracker.config[:rails_version] = $1
20
20
  end
21
21
 
22
+ if @tracker.config[:rails_version] =~ /^(3|4)\./ and not @tracker.options[:rails3]
23
+ @tracker.options[:rails3] = true
24
+ Brakeman.notify "[Notice] Detected Rails #$1 application"
25
+ end
26
+
22
27
  if @tracker.config[:gems][:rails_xss]
23
28
  @tracker.config[:escape_html] = true
24
29
 
@@ -29,6 +29,8 @@ module Brakeman::RouteHelper
29
29
  route = route.value
30
30
  end
31
31
 
32
+ return unless route.is_a? String or route.is_a? Symbol
33
+
32
34
  route = route.to_sym
33
35
 
34
36
  if controller
@@ -47,10 +47,10 @@ class Brakeman::Scanner
47
47
 
48
48
  #Process everything in the Rails application
49
49
  def process
50
- Brakeman.notify "Processing configuration..."
51
- process_config
52
50
  Brakeman.notify "Processing gems..."
53
51
  process_gems
52
+ Brakeman.notify "Processing configuration..."
53
+ process_config
54
54
  Brakeman.notify "Processing initializers..."
55
55
  process_initializers
56
56
  Brakeman.notify "Processing libs..."
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "2.1.2"
2
+ Version = "2.2.0"
3
3
  end
@@ -60,7 +60,9 @@ module Brakeman::WarningCodes
60
60
  :CVE_2013_1856 => 57,
61
61
  :CVE_2013_1857 => 58,
62
62
  :unsafe_symbol_creation => 59,
63
- :dangerous_attr_accessible => 60
63
+ :dangerous_attr_accessible => 60,
64
+ :local_request_config => 61,
65
+ :detailed_exceptions => 62
64
66
  }
65
67
 
66
68
  def self.code name
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
- - 1
9
8
  - 2
10
- version: 2.1.2
9
+ - 0
10
+ version: 2.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Justin Collins
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-09-18 00:00:00 Z
18
+ date: 2013-10-28 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: ruby_parser
@@ -87,12 +87,12 @@ dependencies:
87
87
  requirements:
88
88
  - - ~>
89
89
  - !ruby/object:Gem::Version
90
- hash: 41
90
+ hash: 39
91
91
  segments:
92
92
  - 1
93
93
  - 6
94
- - 19
95
- version: 1.6.19
94
+ - 20
95
+ version: 1.6.20
96
96
  type: :runtime
97
97
  version_requirements: *id005
98
98
  - !ruby/object:Gem::Dependency
@@ -235,6 +235,7 @@ files:
235
235
  - lib/brakeman/warning_codes.rb
236
236
  - lib/brakeman/app_tree.rb
237
237
  - lib/brakeman/checks/check_select_vulnerability.rb
238
+ - lib/brakeman/checks/check_detailed_exceptions.rb
238
239
  - lib/brakeman/checks/check_escape_function.rb
239
240
  - lib/brakeman/checks/check_single_quotes.rb
240
241
  - lib/brakeman/checks/check_model_serialize.rb