brakeman 2.1.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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