brakeman-min 4.3.1 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +24 -1
  3. data/README.md +35 -6
  4. data/bin/brakeman +2 -0
  5. data/lib/brakeman.rb +5 -3
  6. data/lib/brakeman/app_tree.rb +15 -1
  7. data/lib/brakeman/call_index.rb +7 -4
  8. data/lib/brakeman/checks.rb +16 -8
  9. data/lib/brakeman/checks/base_check.rb +2 -19
  10. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +1 -1
  11. data/lib/brakeman/checks/check_content_tag.rb +4 -4
  12. data/lib/brakeman/checks/check_create_with.rb +1 -1
  13. data/lib/brakeman/checks/check_cross_site_scripting.rb +3 -3
  14. data/lib/brakeman/checks/check_default_routes.rb +3 -3
  15. data/lib/brakeman/checks/check_deserialize.rb +1 -1
  16. data/lib/brakeman/checks/check_detailed_exceptions.rb +1 -1
  17. data/lib/brakeman/checks/check_digest_dos.rb +4 -4
  18. data/lib/brakeman/checks/check_escape_function.rb +1 -1
  19. data/lib/brakeman/checks/check_execute.rb +5 -4
  20. data/lib/brakeman/checks/check_file_access.rb +13 -3
  21. data/lib/brakeman/checks/check_file_disclosure.rb +1 -1
  22. data/lib/brakeman/checks/check_filter_skipping.rb +1 -1
  23. data/lib/brakeman/checks/check_forgery_setting.rb +3 -3
  24. data/lib/brakeman/checks/check_header_dos.rb +3 -3
  25. data/lib/brakeman/checks/check_i18n_xss.rb +3 -3
  26. data/lib/brakeman/checks/check_jruby_xml.rb +1 -1
  27. data/lib/brakeman/checks/check_json_encoding.rb +3 -3
  28. data/lib/brakeman/checks/check_json_parsing.rb +8 -11
  29. data/lib/brakeman/checks/check_link_to.rb +3 -3
  30. data/lib/brakeman/checks/check_link_to_href.rb +2 -2
  31. data/lib/brakeman/checks/check_mail_to.rb +3 -3
  32. data/lib/brakeman/checks/check_mime_type_dos.rb +1 -1
  33. data/lib/brakeman/checks/check_model_attributes.rb +4 -4
  34. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  35. data/lib/brakeman/checks/check_nested_attributes.rb +3 -3
  36. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +1 -1
  37. data/lib/brakeman/checks/check_number_to_currency.rb +4 -4
  38. data/lib/brakeman/checks/check_quote_table_name.rb +2 -2
  39. data/lib/brakeman/checks/check_regex_dos.rb +1 -1
  40. data/lib/brakeman/checks/check_render.rb +2 -2
  41. data/lib/brakeman/checks/check_render_dos.rb +1 -1
  42. data/lib/brakeman/checks/check_render_inline.rb +1 -1
  43. data/lib/brakeman/checks/check_response_splitting.rb +1 -1
  44. data/lib/brakeman/checks/check_route_dos.rb +1 -1
  45. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +1 -1
  46. data/lib/brakeman/checks/check_sanitize_methods.rb +3 -3
  47. data/lib/brakeman/checks/check_secrets.rb +1 -1
  48. data/lib/brakeman/checks/check_select_tag.rb +1 -1
  49. data/lib/brakeman/checks/check_select_vulnerability.rb +1 -1
  50. data/lib/brakeman/checks/check_session_manipulation.rb +1 -1
  51. data/lib/brakeman/checks/check_session_settings.rb +1 -1
  52. data/lib/brakeman/checks/check_simple_format.rb +2 -2
  53. data/lib/brakeman/checks/check_single_quotes.rb +14 -10
  54. data/lib/brakeman/checks/check_skip_before_filter.rb +2 -2
  55. data/lib/brakeman/checks/check_sprockets_path_traversal.rb +39 -0
  56. data/lib/brakeman/checks/check_sql.rb +1 -1
  57. data/lib/brakeman/checks/check_sql_cves.rb +2 -2
  58. data/lib/brakeman/checks/check_strip_tags.rb +10 -8
  59. data/lib/brakeman/checks/check_symbol_dos.rb +1 -1
  60. data/lib/brakeman/checks/check_symbol_dos_cve.rb +1 -1
  61. data/lib/brakeman/checks/check_translate_bug.rb +7 -7
  62. data/lib/brakeman/checks/check_unsafe_reflection.rb +1 -1
  63. data/lib/brakeman/checks/check_unscoped_find.rb +1 -1
  64. data/lib/brakeman/checks/check_validation_regex.rb +1 -1
  65. data/lib/brakeman/checks/check_weak_hash.rb +18 -19
  66. data/lib/brakeman/checks/check_xml_dos.rb +1 -1
  67. data/lib/brakeman/checks/check_yaml_parsing.rb +1 -1
  68. data/lib/brakeman/format/style.css +8 -0
  69. data/lib/brakeman/messages.rb +220 -0
  70. data/lib/brakeman/options.rb +13 -0
  71. data/lib/brakeman/parsers/template_parser.rb +2 -2
  72. data/lib/brakeman/processors/alias_processor.rb +7 -0
  73. data/lib/brakeman/processors/config_processor.rb +4 -1
  74. data/lib/brakeman/processors/gem_processor.rb +30 -2
  75. data/lib/brakeman/processors/lib/call_conversion_helper.rb +2 -1
  76. data/lib/brakeman/processors/lib/rails3_route_processor.rb +0 -2
  77. data/lib/brakeman/processors/lib/rails4_config_processor.rb +18 -0
  78. data/lib/brakeman/processors/lib/render_helper.rb +5 -0
  79. data/lib/brakeman/processors/lib/render_path.rb +15 -0
  80. data/lib/brakeman/processors/library_processor.rb +1 -1
  81. data/lib/brakeman/report/report_base.rb +17 -161
  82. data/lib/brakeman/report/report_csv.rb +17 -0
  83. data/lib/brakeman/report/report_html.rb +34 -31
  84. data/lib/brakeman/report/report_json.rb +21 -0
  85. data/lib/brakeman/report/report_markdown.rb +13 -6
  86. data/lib/brakeman/report/report_table.rb +157 -0
  87. data/lib/brakeman/report/report_tabs.rb +3 -1
  88. data/lib/brakeman/report/report_text.rb +16 -0
  89. data/lib/brakeman/scanner.rb +5 -1
  90. data/lib/brakeman/tracker/config.rb +1 -1
  91. data/lib/brakeman/util.rb +0 -17
  92. data/lib/brakeman/version.rb +1 -1
  93. data/lib/brakeman/warning.rb +9 -4
  94. data/lib/brakeman/warning_codes.rb +1 -0
  95. metadata +9 -6
@@ -23,7 +23,7 @@ class Brakeman::CheckXMLDoS < Brakeman::BaseCheck
23
23
 
24
24
  return if has_workaround?
25
25
 
26
- message = "Rails #{version} is vulnerable to denial of service via XML parsing (CVE-2015-3227). Upgrade to Rails version #{fix_version}"
26
+ message = msg(msg_version(version), " is vulnerable to denial of service via XML parsing ", msg_cve("CVE-2015-3227"), ". Upgrade to ", msg_version(fix_version))
27
27
 
28
28
  warn :warning_type => "Denial of Service",
29
29
  :warning_code => :CVE_2015_3227,
@@ -22,7 +22,7 @@ class Brakeman::CheckYAMLParsing < Brakeman::BaseCheck
22
22
  "3.2.11"
23
23
  end
24
24
 
25
- message = "Rails #{rails_version} has a remote code execution vulnerability: upgrade to #{new_version} or disable XML parsing"
25
+ message = msg(msg_version(rails_version), " has a remote code execution vulnerability. Upgrade to ", msg_version(new_version), " or disable XML parsing")
26
26
 
27
27
  warn :warning_type => "Remote Code Execution",
28
28
  :warning_code => :CVE_2013_0156,
@@ -131,3 +131,11 @@ p {
131
131
  div.template_name:hover {
132
132
  background-color: white;
133
133
  }
134
+
135
+ span.code {
136
+ font-family: monospace;
137
+ }
138
+
139
+ span.filename {
140
+ font-family: monospace;
141
+ }
@@ -0,0 +1,220 @@
1
+ module Brakeman
2
+ module Messages
3
+ # Create a new message from a list of messages.
4
+ # Strings are converted to Brakeman::Messages::Plain objects.
5
+ def msg *args
6
+ parts = args.map do |a|
7
+ if a.is_a? String
8
+ Plain.new(a)
9
+ else
10
+ a
11
+ end
12
+ end
13
+
14
+ Message.new(*parts)
15
+ end
16
+
17
+ # Create a new code message fragment
18
+ def msg_code code
19
+ Code.new code
20
+ end
21
+
22
+ # Create a new message fragment with a CVE identifier
23
+ def msg_cve cve
24
+ CVE.new cve
25
+ end
26
+
27
+ # Create a new message fragment representing a file name
28
+ def msg_file str
29
+ Messages::FileName.new str
30
+ end
31
+
32
+ # Create a new message fragment from a user input type (e.g. `:params`).
33
+ # The input type will be converted to a friendly version (e.g. "parameter value").
34
+ def msg_input input
35
+ Input.new input
36
+ end
37
+
38
+ # Create a new message fragment which will not be modified during output
39
+ def msg_lit str
40
+ Literal.new str
41
+ end
42
+
43
+ # Create a new plain string message fragment
44
+ def msg_plain str
45
+ Plain.new str
46
+ end
47
+
48
+ # Create a message fragment representing the version of a library
49
+ def msg_version version, lib = "Rails"
50
+ Version.new version, lib
51
+ end
52
+ end
53
+ end
54
+
55
+ # Class to represent a list of message types
56
+ class Brakeman::Messages::Message
57
+ def initialize *args
58
+ @parts = args.map do |a|
59
+ case a
60
+ when String, Symbol
61
+ Brakeman::Messages::Plain.new(a.to_s)
62
+ else
63
+ a
64
+ end
65
+ end
66
+ end
67
+
68
+ def << msg
69
+ if msg.is_a? String
70
+ @parts << Brakeman::Messages::Plain.new(msg)
71
+ else
72
+ @parts << msg
73
+ end
74
+ end
75
+
76
+ def to_s
77
+ output = @parts.map(&:to_s).join
78
+
79
+ case @parts.first
80
+ when Brakeman::Messages::Code, Brakeman::Messages::Literal, Brakeman::Messages::Version
81
+ else
82
+ output[0] = output[0].capitalize
83
+ end
84
+
85
+ output
86
+ end
87
+
88
+ def to_html
89
+ require 'cgi'
90
+
91
+ output = @parts.map(&:to_html).join
92
+
93
+ case @parts.first
94
+ when Brakeman::Messages::Code, Brakeman::Messages::Literal, Brakeman::Messages::Version
95
+ else
96
+ output[0] = output[0].capitalize
97
+ end
98
+
99
+ output
100
+ end
101
+ end
102
+
103
+ class Brakeman::Messages::Code
104
+ def initialize code
105
+ @code = code.to_s
106
+ end
107
+
108
+ def to_s
109
+ "`#{@code}`"
110
+ end
111
+
112
+ def to_html
113
+ "<span class=\"code\">#{CGI.escapeHTML(@code)}</span>"
114
+ end
115
+ end
116
+
117
+ class Brakeman::Messages::CVE
118
+ def initialize cve
119
+ @cve = cve
120
+ end
121
+
122
+ def to_s
123
+ "(#{@cve})"
124
+ end
125
+
126
+ def to_html
127
+ "(<a href=\"https://cve.mitre.org/cgi-bin/cvename.cgi?name=#{@cve}\" target=\"_blank\" rel=\"noreferrer\">#{@cve}</a>)"
128
+ end
129
+ end
130
+
131
+ class Brakeman::Messages::FileName
132
+ def initialize file
133
+ @file = file
134
+ end
135
+
136
+ def to_s
137
+ "`#{@file}`"
138
+ end
139
+
140
+ def to_html
141
+ "<span class=\"filename\">#{CGI.escapeHTML(@file)}</span>"
142
+ end
143
+ end
144
+
145
+ class Brakeman::Messages::Input
146
+ def initialize input
147
+ @input = input
148
+ @value = friendly_type_of(@input)
149
+ end
150
+
151
+ def friendly_type_of input_type
152
+ if input_type.is_a? Brakeman::BaseCheck::Match
153
+ input_type = input_type.type
154
+ end
155
+
156
+ case input_type
157
+ when :params
158
+ "parameter value"
159
+ when :cookies
160
+ "cookie value"
161
+ when :request
162
+ "request value"
163
+ when :model
164
+ "model attribute"
165
+ else
166
+ "user input"
167
+ end
168
+ end
169
+
170
+ def to_s
171
+ @value
172
+ end
173
+
174
+ def to_html
175
+ self.to_s
176
+ end
177
+ end
178
+
179
+ class Brakeman::Messages::Literal
180
+ def initialize value
181
+ @value = value.to_s
182
+ end
183
+
184
+ def to_s
185
+ @value
186
+ end
187
+
188
+ def to_html
189
+ @value
190
+ end
191
+ end
192
+
193
+ class Brakeman::Messages::Plain
194
+ def initialize string
195
+ @value = string
196
+ end
197
+
198
+ def to_s
199
+ @value
200
+ end
201
+
202
+ def to_html
203
+ CGI.escapeHTML(@value)
204
+ end
205
+ end
206
+
207
+ class Brakeman::Messages::Version
208
+ def initialize version, lib
209
+ @version = version
210
+ @library = lib
211
+ end
212
+
213
+ def to_s
214
+ "#{@library} #{@version}"
215
+ end
216
+
217
+ def to_html
218
+ CGI.escapeHTML(self.to_s)
219
+ end
220
+ end
@@ -169,6 +169,19 @@ module Brakeman::Options
169
169
  options[:engine_paths].merge paths
170
170
  end
171
171
 
172
+ opts.on "-E", "--enable Check1,Check2,etc", Array, "Enable the specified checks" do |checks|
173
+ checks.map! do |check|
174
+ if check.start_with? "Check"
175
+ check
176
+ else
177
+ "Check" << check
178
+ end
179
+ end
180
+
181
+ options[:enable_checks] ||= Set.new
182
+ options[:enable_checks].merge checks
183
+ end
184
+
172
185
  opts.on "-t", "--test Check1,Check2,etc", Array, "Only run the specified checks" do |checks|
173
186
  checks.each_with_index do |s, index|
174
187
  if s[0,5] != "Check"
@@ -59,9 +59,9 @@ module Brakeman
59
59
  else
60
60
  require 'erb'
61
61
  src = if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
62
- ERB.new(text, trim_mode: path).src
62
+ ERB.new(text, trim_mode: '-').src
63
63
  else
64
- ERB.new(text, nil, path).src
64
+ ERB.new(text, nil, '-').src
65
65
  end
66
66
  src.sub!(/^#.*\n/, '') if Brakeman::Scanner::RUBY_1_9
67
67
  src
@@ -731,6 +731,13 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
731
731
  exp[2 + i] = process_if_branch branch
732
732
  end
733
733
  else
734
+ # Translate `if !...` into `unless ...`
735
+ # Technically they are different but that's only if someone overrides `!`
736
+ if call? condition and condition.method == :!
737
+ condition = condition.target
738
+ exps.reverse!
739
+ end
740
+
734
741
  was_inside = @inside_if
735
742
  @inside_if = true
736
743
 
@@ -1,11 +1,14 @@
1
1
  require 'brakeman/processors/base_processor'
2
2
  require 'brakeman/processors/alias_processor'
3
+ require 'brakeman/processors/lib/rails4_config_processor.rb'
3
4
  require 'brakeman/processors/lib/rails3_config_processor.rb'
4
5
  require 'brakeman/processors/lib/rails2_config_processor.rb'
5
6
 
6
7
  class Brakeman::ConfigProcessor
7
8
  def self.new tracker
8
- if tracker.options[:rails3]
9
+ if tracker.options[:rails4]
10
+ Brakeman::Rails4ConfigProcessor.new tracker
11
+ elsif tracker.options[:rails3]
9
12
  Brakeman::Rails3ConfigProcessor.new tracker
10
13
  else
11
14
  Brakeman::Rails2ConfigProcessor.new tracker
@@ -10,8 +10,17 @@ class Brakeman::GemProcessor < Brakeman::BasicProcessor
10
10
 
11
11
  def process_gems gem_files
12
12
  @gem_files = gem_files
13
- @gemfile = gem_files[:gemfile][:file]
14
- process gem_files[:gemfile][:src]
13
+ @gemfile = gem_files[:gemfile] && gem_files[:gemfile][:file]
14
+ @gemspec = gem_files[:gemspec] && gem_files[:gemspec][:file]
15
+
16
+
17
+ if @gemspec
18
+ process gem_files[:gemspec][:src]
19
+ end
20
+
21
+ if @gemfile
22
+ process gem_files[:gemfile][:src]
23
+ end
15
24
 
16
25
  if gem_files[:gemlock]
17
26
  process_gem_lock
@@ -41,11 +50,30 @@ class Brakeman::GemProcessor < Brakeman::BasicProcessor
41
50
  @tracker.config.set_ruby_version version.value
42
51
  end
43
52
  end
53
+ elsif @inside_gemspec and exp.method == :add_dependency
54
+ if string? exp.first_arg and string? exp.last_arg
55
+ @tracker.config.add_gem exp.first_arg.value, exp.last_arg.value, @gemspec, exp.line
56
+ end
44
57
  end
45
58
 
46
59
  exp
47
60
  end
48
61
 
62
+ GEM_SPEC = s(:colon2, s(:const, :Gem), :Specification)
63
+
64
+ def process_iter exp
65
+ if exp.block_call.target == GEM_SPEC and exp.block_call.method == :new
66
+ @inside_gemspec = true
67
+ process exp.block if sexp? exp.block
68
+
69
+ exp
70
+ else
71
+ process_default exp
72
+ end
73
+ ensure
74
+ @inside_gemspec = false
75
+ end
76
+
49
77
  def process_gem_lock
50
78
  line_num = 1
51
79
  file = @gem_files[:gemlock][:file]
@@ -9,7 +9,8 @@ module Brakeman
9
9
  # Join two array literals into one.
10
10
  def join_arrays lhs, rhs, original_exp = nil
11
11
  if array? lhs and array? rhs
12
- result = Sexp.new(:array).line(lhs.line)
12
+ result = Sexp.new(:array)
13
+ result.line(lhs.line || rhs.line)
13
14
  result.concat lhs[1..-1]
14
15
  result.concat rhs[1..-1]
15
16
  result
@@ -183,8 +183,6 @@ class Brakeman::Rails3RoutesProcessor < Brakeman::BasicProcessor
183
183
  else
184
184
  add_route route[1], route[0]
185
185
  end
186
- elsif in_controller_block? and symbol? first_arg
187
- add_route first_arg
188
186
  else hash? first_arg
189
187
  hash_iterate first_arg do |k, v|
190
188
  if string? k
@@ -0,0 +1,18 @@
1
+ require 'brakeman/processors/lib/rails3_config_processor'
2
+
3
+ class Brakeman::Rails4ConfigProcessor < Brakeman::Rails3ConfigProcessor
4
+ APPLICATION_CONFIG = s(:call, s(:call, s(:const, :Rails), :application), :configure)
5
+
6
+ # Look for Rails.application.configure do ... end
7
+ def process_iter exp
8
+ if exp.block_call == APPLICATION_CONFIG
9
+ @inside_config = true
10
+ process exp.block if sexp? exp.block
11
+ @inside_config = false
12
+ else
13
+ super
14
+ end
15
+
16
+ exp
17
+ end
18
+ end
@@ -65,6 +65,11 @@ module Brakeman::RenderHelper
65
65
  return
66
66
  end
67
67
 
68
+ if called_from
69
+ # Track actual template that was rendered
70
+ called_from.last_template = template
71
+ end
72
+
68
73
  template_env = only_ivars(:include_request_vars)
69
74
 
70
75
  #Hash the environment and the source of the template to avoid
@@ -29,6 +29,17 @@ module Brakeman
29
29
  self
30
30
  end
31
31
 
32
+ def last_template= template
33
+ if @path.last
34
+ @path.last[:rendered] = {
35
+ name: template.name,
36
+ file: template.file,
37
+ }
38
+ else
39
+ Brakeman.debug "[Notice] No render path to add template information"
40
+ end
41
+ end
42
+
32
43
  def include_template? name
33
44
  name = name.to_sym
34
45
 
@@ -71,6 +82,10 @@ module Brakeman
71
82
  @path.length
72
83
  end
73
84
 
85
+ def map &block
86
+ @path.map &block
87
+ end
88
+
74
89
  def to_a
75
90
  @path.map do |loc|
76
91
  case loc[:type]