brakeman 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -93,6 +93,14 @@ By default, Brakeman will return 0 as an exit code unless something went very wr
93
93
 
94
94
  brakeman -z
95
95
 
96
+ To skip certain files that Brakeman may have trouble parsing, use:
97
+
98
+ brakeman --skip-files file1,file2,etc
99
+
100
+ Brakeman will raise warnings on models that use `attr_protected`. To suppress these warnings:
101
+
102
+ brakeman --ignore-protected
103
+
96
104
  # Warning information
97
105
 
98
106
  See WARNING_TYPES for more information on the warnings reported by this tool.
@@ -131,7 +139,7 @@ The `-c` option can be used to specify a configuration file to use.
131
139
 
132
140
  The MIT License
133
141
 
134
- Copyright (c) 2010, YELLOWPAGES.COM, LLC
142
+ Copyright (c) 2010-2012, YELLOWPAGES.COM, LLC
135
143
 
136
144
  Permission is hereby granted, free of charge, to any person obtaining a copy
137
145
  of this software and associated documentation files (the "Software"), to deal
data/bin/brakeman CHANGED
@@ -42,9 +42,9 @@ unless options[:app_path]
42
42
  end
43
43
 
44
44
  #Run scan and output a report
45
- clean = Brakeman.run options.merge(:print_report => true, :quiet => options[:quiet])
45
+ tracker = Brakeman.run options.merge(:print_report => true, :quiet => options[:quiet])
46
46
 
47
47
  #Return error code if --exit-on-warn is used and warnings were found
48
- if options[:exit_on_warn] and not clean
48
+ if options[:exit_on_warn] and not tracker.checks.all_warnings.empty?
49
49
  exit Brakeman::Warnings_Found_Exit_Code
50
50
  end
data/lib/brakeman.rb CHANGED
@@ -262,15 +262,6 @@ module Brakeman
262
262
  puts tracker.report.send(options[:output_format])
263
263
  end
264
264
 
265
- if options[:exit_on_warn]
266
- tracker.checks.all_warnings.each do |warning|
267
- next if warning.confidence > options[:min_confidence]
268
- return false
269
- end
270
-
271
- return true
272
- end
273
-
274
265
  tracker
275
266
  end
276
267
 
@@ -20,7 +20,13 @@ class Brakeman::Checks
20
20
  end
21
21
 
22
22
  #No need to use this directly.
23
- def initialize
23
+ def initialize options = { }
24
+ if options[:min_confidence]
25
+ @min_confidence = options[:min_confidence]
26
+ else
27
+ @min_confidence = Brakeman.get_defaults[:min_confidence]
28
+ end
29
+
24
30
  @warnings = []
25
31
  @template_warnings = []
26
32
  @model_warnings = []
@@ -31,18 +37,22 @@ class Brakeman::Checks
31
37
  #Add Warning to list of warnings to report.
32
38
  #Warnings are split into four different arrays
33
39
  #for template, controller, model, and generic warnings.
40
+ #
41
+ #Will not add warnings which are below the minimum confidence level.
34
42
  def add_warning warning
35
- case warning.warning_set
36
- when :template
37
- @template_warnings << warning
38
- when :warning
39
- @warnings << warning
40
- when :controller
41
- @controller_warnings << warning
42
- when :model
43
- @model_warnings << warning
44
- else
45
- raise "Unknown warning: #{warning.warning_set}"
43
+ unless warning.confidence > @min_confidence
44
+ case warning.warning_set
45
+ when :template
46
+ @template_warnings << warning
47
+ when :warning
48
+ @warnings << warning
49
+ when :controller
50
+ @controller_warnings << warning
51
+ when :model
52
+ @model_warnings << warning
53
+ else
54
+ raise "Unknown warning: #{warning.warning_set}"
55
+ end
46
56
  end
47
57
  end
48
58
 
@@ -80,7 +90,7 @@ class Brakeman::Checks
80
90
 
81
91
  #Run checks sequentially
82
92
  def self.run_checks_sequential tracker
83
- check_runner = self.new
93
+ check_runner = self.new :min_confidence => tracker.options[:min_confidence]
84
94
 
85
95
  @checks.each do |c|
86
96
  check_name = get_check_name c
@@ -111,7 +121,7 @@ class Brakeman::Checks
111
121
  def self.run_checks_parallel tracker
112
122
  threads = []
113
123
 
114
- check_runner = self.new
124
+ check_runner = self.new :min_confidence => tracker.options[:min_confidence]
115
125
 
116
126
  @checks.each do |c|
117
127
  check_name = get_check_name c
@@ -71,6 +71,8 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
71
71
  end
72
72
 
73
73
  def check_for_immediate_xss exp
74
+ return if duplicate? exp
75
+
74
76
  if exp[0] == :output
75
77
  out = exp[1]
76
78
  elsif exp[0] == :escaped_output and raw_call? exp
@@ -79,7 +81,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
79
81
 
80
82
  type, match = has_immediate_user_input? out
81
83
 
82
- if type and not duplicate? exp
84
+ if type
83
85
  add_result exp
84
86
  case type
85
87
  when :params
@@ -102,7 +104,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
102
104
  elsif not tracker.options[:ignore_model_output] and match = has_immediate_model?(out)
103
105
  method = match[2]
104
106
 
105
- unless duplicate? out or IGNORE_MODEL_METHODS.include? method
107
+ unless IGNORE_MODEL_METHODS.include? method
106
108
  add_result out
107
109
 
108
110
  if MODEL_METHODS.include? method or method.to_s =~ /^find_by/
@@ -34,6 +34,8 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
34
34
  end
35
35
 
36
36
  def process_result result
37
+ return if duplicate? result
38
+
37
39
  #Have to make a copy of this, otherwise it will be changed to
38
40
  #an ignored method call by the code above.
39
41
  call = result[:call] = result[:call].dup
@@ -58,19 +60,15 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
58
60
  message = "Unescaped user input value in link_to"
59
61
  end
60
62
 
61
- unless duplicate? result
62
- add_result result
63
-
64
- warn :result => result,
65
- :warning_type => "Cross Site Scripting",
66
- :message => message,
67
- :confidence => CONFIDENCE[:high]
68
- end
69
-
63
+ add_result result
64
+ warn :result => result,
65
+ :warning_type => "Cross Site Scripting",
66
+ :message => message,
67
+ :confidence => CONFIDENCE[:high]
70
68
  elsif not tracker.options[:ignore_model_output] and match = has_immediate_model?(first_arg)
71
69
  method = match[2]
72
70
 
73
- unless duplicate? result or IGNORE_MODEL_METHODS.include? method
71
+ unless IGNORE_MODEL_METHODS.include? method
74
72
  add_result result
75
73
 
76
74
  if MODEL_METHODS.include? method or method.to_s =~ /^find_by/
@@ -92,7 +90,7 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
92
90
  message = "Unescaped parameter value in link_to"
93
91
  end
94
92
 
95
- if message and not duplicate? result
93
+ if message
96
94
  add_result result
97
95
 
98
96
  warn :result => result,
@@ -0,0 +1,90 @@
1
+ require 'brakeman/checks/check_cross_site_scripting'
2
+
3
+ #Checks for calls to link_to which pass in potentially hazardous data
4
+ #to the second argument. While this argument must be html_safe to not break
5
+ #the html, it must also be url safe as determined by calling a
6
+ #:url_safe_method. This prevents attacks such as javascript:evil() or
7
+ #data:<encoded XSS> which is html_safe, but not safe as an href
8
+ #Props to Nick Green for the idea.
9
+ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
10
+ Brakeman::Checks.add self
11
+
12
+ @description = "Checks to see if values used for hrefs are sanitized using a :url_safe_method to protect against javascript:/data: XSS"
13
+
14
+ def run_check
15
+ @ignore_methods = Set.new([:button_to, :check_box,
16
+ :field_field, :fields_for, :hidden_field,
17
+ :hidden_field, :hidden_field_tag, :image_tag, :label,
18
+ :mail_to, :radio_button, :select,
19
+ :submit_tag, :text_area, :text_field,
20
+ :text_field_tag, :url_encode, :url_for,
21
+ :will_paginate] ).merge(tracker.options[:url_safe_methods] || [])
22
+
23
+ @models = tracker.models.keys
24
+ @inspect_arguments = tracker.options[:check_arguments]
25
+
26
+ methods = tracker.find_call :target => false, :method => :link_to
27
+ methods.each do |call|
28
+ process_result call
29
+ end
30
+ end
31
+
32
+ def process_result result
33
+ #Have to make a copy of this, otherwise it will be changed to
34
+ #an ignored method call by the code above.
35
+ call = result[:call] = result[:call].dup
36
+ @matched = false
37
+ url_arg = process call[3][2]
38
+
39
+ #Ignore situations where the href is an interpolated string
40
+ #with something before the user input
41
+ return if node_type?(url_arg, :string_interp) && !url_arg[1].chomp.empty?
42
+
43
+ type, match = has_immediate_user_input? url_arg
44
+
45
+ if type
46
+ case type
47
+ when :params
48
+ message = "Unsafe parameter value in link_to href"
49
+ when :cookies
50
+ message = "Unsafe cookie value in link_to href"
51
+ else
52
+ message = "Unsafe user input value in link_to href"
53
+ end
54
+
55
+ unless duplicate? result
56
+ add_result result
57
+ warn :result => result,
58
+ :warning_type => "Cross Site Scripting",
59
+ :message => message,
60
+ :confidence => CONFIDENCE[:high]
61
+ end
62
+ elsif has_immediate_model? url_arg
63
+
64
+ # Decided NOT warn on models. polymorphic_path is called it a model is
65
+ # passed to link_to (which passes it to url_for)
66
+
67
+ elsif hash? url_arg
68
+
69
+ # url_for uses the key/values pretty carefully and I don't see a risk.
70
+ # IF you have default routes AND you accept user input for :controller
71
+ # and :only_path, then MAYBE you could trigger a javascript:/data:
72
+ # attack.
73
+
74
+ elsif @matched
75
+ if @matched == :model and not tracker.options[:ignore_model_output]
76
+ message = "Unsafe model attribute in link_to href"
77
+ elsif @matched == :params
78
+ message = "Unsafe parameter value in link_to href"
79
+ end
80
+
81
+ if message and not duplicate? result
82
+ add_result result
83
+ warn :result => result,
84
+ :warning_type => "Cross Site Scripting",
85
+ :message => message,
86
+ :confidence => CONFIDENCE[:med]
87
+ end
88
+ end
89
+ end
90
+ end
@@ -30,7 +30,8 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
30
30
  :update_attributes,
31
31
  :update_attributes!,
32
32
  :create,
33
- :create!]
33
+ :create!,
34
+ :build]
34
35
 
35
36
  Brakeman.debug "Processing possible mass assignment calls"
36
37
  calls.each do |result|
@@ -181,7 +181,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
181
181
  arg.each do |exp|
182
182
  #For now, don't warn on interpolation of Model.table_name
183
183
  #but check for other 'safe' things in the future
184
- if sexp? exp and (exp.node_type == :string_eval or exp.node_type == :evstr)
184
+ if node_type? exp, :string_eval, :evstr
185
185
  if call? exp[1] and (model_name?(exp[1][1]) or exp[1][1].nil?) and exp[1][2] == :table_name
186
186
  return false
187
187
  end
@@ -84,6 +84,11 @@ module Brakeman::Options
84
84
  options[:safe_methods].merge methods.map {|e| e.to_sym }
85
85
  end
86
86
 
87
+ opts.on "--url-safe-methods method1,method2,etc", Array, "Do not warn of XSS if the link_to href parameter is wrapped in a safe method" do |methods|
88
+ options[:url_safe_methods] ||= Set.new
89
+ options[:url_safe_methods].merge methods.map {|e| e.to_sym }
90
+ end
91
+
87
92
  opts.on "--skip-files file1,file2,etc", Array, "Skip processing of these files" do |files|
88
93
  options[:skip_files] ||= Set.new
89
94
  options[:skip_files].merge files.map {|f| f.to_sym }
@@ -85,7 +85,7 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
85
85
  else
86
86
  Brakeman.debug "[Notice] Layout not found: #{name}"
87
87
  end
88
- elsif sexp? args[-1] and (args[-1][0] == :nil or args[-1][0] == :false)
88
+ elsif node_type? args[-1], :nil, :false
89
89
  #layout :false or layout nil
90
90
  @controller[:layout] = false
91
91
  end
@@ -181,7 +181,7 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
181
181
  block_variable = :temp
182
182
  end
183
183
 
184
- if sexp? exp[3] and exp[3].node_type == :block
184
+ if node_type? exp[3], :block
185
185
  block_inner = exp[3][1..-1]
186
186
  else
187
187
  block_inner = [exp[3]]
@@ -68,7 +68,7 @@ class Brakeman::ErbTemplateProcessor < Brakeman::TemplateProcessor
68
68
  res = process e
69
69
  if res.empty? or res == ignore
70
70
  nil
71
- elsif sexp? res and res.node_type == :lvar and res[1] == :_erbout
71
+ elsif node_type?(res, :lvar) and res[1] == :_erbout
72
72
  nil
73
73
 
74
74
  else
@@ -138,7 +138,7 @@ class Brakeman::FindAllCalls < Brakeman::BaseProcessor
138
138
  #Returns method chain as an array
139
139
  #For example, User.human.alive.all would return [:User, :human, :alive, :all]
140
140
  def get_chain call
141
- if sexp? call and (call.node_type == :call or call.node_type == :attrasgn)
141
+ if node_type? call, :call, :attrasgn
142
142
  get_chain(call[1]) + [call[2]]
143
143
  else
144
144
  [get_target(call)]
@@ -107,7 +107,7 @@ class Brakeman::FindCall < Brakeman::BaseProcessor
107
107
  # User.find(:first, :conditions => "user = '#{params['user']}').name
108
108
  #
109
109
  #A search for User.find will not match this unless @in_depth is true.
110
- if @in_depth and sexp? exp[1] and exp[1][0] == :call
110
+ if @in_depth and node_type? exp[1], :call
111
111
  process exp[1]
112
112
  end
113
113
 
@@ -103,7 +103,7 @@ class Brakeman::Rails2ConfigProcessor < Brakeman::BaseProcessor
103
103
  #
104
104
  # [:action_controller, :session_store]
105
105
  def get_rails_config exp
106
- if sexp? exp and exp.node_type == :attrasgn
106
+ if node_type? exp, :attrasgn
107
107
  attribute = exp[2].to_s[0..-2].to_sym
108
108
  get_rails_config(exp[1]) << attribute
109
109
  elsif call? exp
@@ -89,7 +89,7 @@ class Brakeman::Rails2RoutesProcessor < Brakeman::BaseProcessor
89
89
  process_resource_options exp[-1]
90
90
  else
91
91
  exp.each do |argument|
92
- if sexp? argument and argument.node_type == :lit
92
+ if node_type? argument, :lit
93
93
  self.current_controller = exp[0][1]
94
94
  add_resources_routes
95
95
  process_resource_options exp[-1]
@@ -165,7 +165,7 @@ class Brakeman::Rails2RoutesProcessor < Brakeman::BaseProcessor
165
165
  process_resource_options exp[-1]
166
166
  else
167
167
  exp.each do |argument|
168
- if sexp? argument and argument.node_type == :lit
168
+ if node_type? argument, :lit
169
169
  self.current_controller = pluralize(exp[0][1].to_s)
170
170
  add_resource_routes
171
171
  process_resource_options exp[-1]
@@ -29,7 +29,7 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BaseProcessor
29
29
 
30
30
  #Look for MyApp::Application.configure do ... end
31
31
  def process_iter exp
32
- if sexp?(exp[1][1]) and exp[1][1][0] == :colon2 and exp[1][1][2] == :Application
32
+ if node_type?(exp[1][1], :colon2) and exp[1][1][2] == :Application
33
33
  @inside_config = true
34
34
  process exp[-1] if sexp? exp[-1]
35
35
  @inside_config = false
@@ -100,7 +100,7 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BaseProcessor
100
100
  #
101
101
  # [:action_controller, :session_store]
102
102
  def get_rails_config exp
103
- if sexp? exp and exp.node_type == :attrasgn
103
+ if node_type? exp, :attrasgn
104
104
  attribute = exp[2].to_s[0..-2].to_sym
105
105
  get_rails_config(exp[1]) << attribute
106
106
  elsif call? exp
@@ -75,7 +75,7 @@ module Brakeman::RenderHelper
75
75
  #Process layout
76
76
  if string? options[:layout]
77
77
  process_template "layouts/#{options[:layout][1]}", nil
78
- elsif sexp? options[:layout] and options[:layout][0] == :false
78
+ elsif node_type? options[:layout], :false
79
79
  #nothing
80
80
  elsif not template[:name].to_s.match(/[^\/_][^\/]+$/)
81
81
  #Don't do this for partials
@@ -40,7 +40,7 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
40
40
 
41
41
  #Check for e.g. Model.find.each do ... end
42
42
  if method == :each and args and block and model = get_model_target(target)
43
- if sexp? args and args.node_type == :lasgn
43
+ if node_type? args, :lasgn
44
44
  if model == target[1]
45
45
  env[Sexp.new(:lvar, args[1])] = Sexp.new(:call, model, :new, Sexp.new(:arglist))
46
46
  else
@@ -50,7 +50,7 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
50
50
  process block if sexp? block
51
51
  end
52
52
  elsif FORM_METHODS.include? method
53
- if sexp? args and args.node_type == :lasgn
53
+ if node_type? args, :lasgn
54
54
  env[Sexp.new(:lvar, args[1])] = Sexp.new(:call, Sexp.new(:const, :FormBuilder), :new, Sexp.new(:arglist))
55
55
 
56
56
  process block if sexp? block
@@ -102,7 +102,6 @@ class Brakeman::Report
102
102
  def generate_warnings html = false
103
103
  table = Ruport::Data::Table(["Confidence", "Class", "Method", "Warning Type", "Message"])
104
104
  checks.warnings.each do |warning|
105
- next if warning.confidence > tracker.options[:min_confidence]
106
105
  w = warning.to_row
107
106
 
108
107
  if html
@@ -132,7 +131,6 @@ class Brakeman::Report
132
131
  unless checks.template_warnings.empty?
133
132
  table = Ruport::Data::Table(["Confidence", "Template", "Warning Type", "Message"])
134
133
  checks.template_warnings.each do |warning|
135
- next if warning.confidence > tracker.options[:min_confidence]
136
134
  w = warning.to_row :template
137
135
 
138
136
  if html
@@ -163,7 +161,6 @@ class Brakeman::Report
163
161
  unless checks.model_warnings.empty?
164
162
  table = Ruport::Data::Table(["Confidence", "Model", "Warning Type", "Message"])
165
163
  checks.model_warnings.each do |warning|
166
- next if warning.confidence > tracker.options[:min_confidence]
167
164
  w = warning.to_row :model
168
165
 
169
166
  if html
@@ -194,7 +191,6 @@ class Brakeman::Report
194
191
  unless checks.controller_warnings.empty?
195
192
  table = Ruport::Data::Table(["Confidence", "Controller", "Warning Type", "Message"])
196
193
  checks.controller_warnings.each do |warning|
197
- next if warning.confidence > tracker.options[:min_confidence]
198
194
  w = warning.to_row :controller
199
195
 
200
196
  if html
@@ -483,13 +479,10 @@ class Brakeman::Report
483
479
  checks.template_warnings].each do |warnings|
484
480
 
485
481
  warnings.each do |warning|
486
- unless warning.confidence > tracker.options[:min_confidence]
482
+ summary[warning.warning_type.to_s] += 1
487
483
 
488
- summary[warning.warning_type.to_s] += 1
489
-
490
- if warning.confidence == 0
491
- high_confidence_warnings += 1
492
- end
484
+ if warning.confidence == 0
485
+ high_confidence_warnings += 1
493
486
  end
494
487
  end
495
488
  end
@@ -586,7 +579,6 @@ class Brakeman::Report
586
579
  [:model_warnings, "Model"], [:template_warnings, "Template"]].map do |meth, category|
587
580
 
588
581
  checks.send(meth).map do |w|
589
- next if w.confidence > tracker.options[:min_confidence]
590
582
  line = w.line || 0
591
583
  w.warning_type.gsub!(/[^\w\s]/, ' ')
592
584
  "#{file_for w}\t#{line}\t#{w.warning_type}\t#{category}\t#{w.format_message}\t#{TEXT_CONFIDENCE[w.confidence]}"
@@ -618,4 +610,10 @@ class Brakeman::Report
618
610
 
619
611
  report
620
612
  end
613
+
614
+ def to_json
615
+ require 'json'
616
+
617
+ @checks.all_warnings.map { |w| w.to_hash }.to_json
618
+ end
621
619
  end
@@ -256,31 +256,34 @@ class Brakeman::RescanReport
256
256
  #Output total, fixed, and new warnings
257
257
  def to_s(verbose = false)
258
258
  if !verbose
259
- <<-OUTPUT
259
+ <<-OUTPUT
260
260
  Total warnings: #{all_warnings.length}
261
261
  Fixed warnings: #{fixed_warnings.length}
262
262
  New warnings: #{new_warnings.length}
263
- OUTPUT
263
+ OUTPUT
264
264
  else
265
- existing_warnings = all_warnings - new_warnings
266
-
267
- "".tap do |out|
268
- {:fixed => fixed_warnings, :new => new_warnings, :existing => existing_warnings}.each do |warning_type, warnings|
269
- if warnings.length > 0
270
- out << "#{warning_type.to_s.titleize} warnings: #{warnings.length}\n"
271
- table = Ruport::Data::Table(["Confidence", "Class", "Method", "Warning Type", "Message"])
272
- warnings.sort_by{|w| w.confidence}.each do |warning|
273
- next if warning.confidence > @tracker.options[:min_confidence]
274
- w = warning.to_row
275
- w["Confidence"] = Brakeman::Report::TEXT_CONFIDENCE[w["Confidence"]] if w["Confidence"].is_a?(Numeric)
276
- table << warning.to_row
277
- end
278
- out << table.to_s
265
+ #Eventually move this to different method, or make default to_s
266
+ out = ""
267
+
268
+ {:fixed => fixed_warnings, :new => new_warnings, :existing => existing_warnings}.each do |warning_type, warnings|
269
+ if warnings.length > 0
270
+ out << "#{warning_type.to_s.titleize} warnings: #{warnings.length}\n"
271
+
272
+ table = Ruport::Data::Table(["Confidence", "Class", "Method", "Warning Type", "Message"])
273
+
274
+ warnings.sort_by { |w| w.confidence}.each do |warning|
275
+ w = warning.to_row
276
+
277
+ w["Confidence"] = Brakeman::Report::TEXT_CONFIDENCE[w["Confidence"]]
278
+
279
+ table << w
279
280
  end
280
281
 
282
+ out << table.to_s
281
283
  end
282
284
  end
283
285
 
286
+ out
284
287
  end
285
288
  end
286
289
  end
@@ -300,9 +300,9 @@ class Brakeman::Scanner
300
300
  if tracker.config[:escape_html]
301
301
  type = :erubis
302
302
  if options[:rails3]
303
- src = Brakeman::RailsXSSErubis.new(text).src
303
+ src = Brakeman::Rails3XSSErubis.new(text).src
304
304
  else
305
- src = Brakeman::ErubisEscape.new(text).src
305
+ src = Brakeman::Rails2XSSErubis.new(text).src
306
306
  end
307
307
  elsif tracker.config[:erubis]
308
308
  type = :erubis
@@ -382,12 +382,13 @@ class Brakeman::Scanner
382
382
  end
383
383
 
384
384
  #This is from Rails 3 version of the Erubis handler
385
- class Brakeman::RailsXSSErubis < ::Erubis::Eruby
385
+ class Brakeman::Rails3XSSErubis < ::Erubis::Eruby
386
386
 
387
387
  def add_preamble(src)
388
388
  # src << "_buf = ActionView::SafeBuffer.new;\n"
389
389
  end
390
390
 
391
+ #This is different from Rails 3 - fixes some line number issues
391
392
  def add_text(src, text)
392
393
  if text == "\n"
393
394
  src << "\n"
@@ -441,3 +442,54 @@ class Brakeman::RailsXSSErubis < ::Erubis::Eruby
441
442
  end
442
443
  end
443
444
 
445
+ #This is from the rails_xss plugin for Rails 2
446
+ class Brakeman::Rails2XSSErubis < ::Erubis::Eruby
447
+ def add_preamble(src)
448
+ #src << "@output_buffer = ActiveSupport::SafeBuffer.new;"
449
+ end
450
+
451
+ def add_text(src, text)
452
+ return if text.empty?
453
+ src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
454
+ end
455
+
456
+ #This is different from rails_xss - fixes some line number issues
457
+ def add_text(src, text)
458
+ if text == "\n"
459
+ src << "\n"
460
+ elsif text.include? "\n"
461
+ lines = text.split("\n")
462
+ if text.match(/\n\z/)
463
+ lines.each do |line|
464
+ src << "@output_buffer.safe_concat('" << escape_text(line) << "');\n"
465
+ end
466
+ else
467
+ lines[0..-2].each do |line|
468
+ src << "@output_buffer.safe_concat('" << escape_text(line) << "');\n"
469
+ end
470
+
471
+ src << "@output_buffer.safe_concat('" << escape_text(lines.last) << "');"
472
+ end
473
+ else
474
+ src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
475
+ end
476
+ end
477
+
478
+ BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
479
+
480
+ def add_expr_literal(src, code)
481
+ if code =~ BLOCK_EXPR
482
+ src << "@output_buffer.safe_concat((" << $1 << ").to_s);"
483
+ else
484
+ src << '@output_buffer << ((' << code << ').to_s);'
485
+ end
486
+ end
487
+
488
+ def add_expr_escaped(src, code)
489
+ src << '@output_buffer << ' << escaped_expr(code) << ';'
490
+ end
491
+
492
+ def add_postamble(src)
493
+ #src << '@output_buffer.to_s'
494
+ end
495
+ end
data/lib/brakeman/util.rb CHANGED
@@ -192,6 +192,11 @@ module Brakeman::Util
192
192
  exp.is_a? Sexp
193
193
  end
194
194
 
195
+ #Check if _exp_ is a Sexp and the node type matches one of the given types.
196
+ def node_type? exp, *types
197
+ exp.is_a? Sexp and types.include? exp.node_type
198
+ end
199
+
195
200
  #Return file name related to given warning. Uses +warning.file+ if it exists
196
201
  def file_for warning, tracker = nil
197
202
  if tracker.nil?
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "1.3.0"
2
+ Version = "1.4.0"
3
3
  end
@@ -51,7 +51,7 @@ class Brakeman::Warning
51
51
  end
52
52
 
53
53
  def hash
54
- self.format_message.hash
54
+ self.to_s.hash
55
55
  end
56
56
 
57
57
  def eql? other_warning
@@ -93,8 +93,6 @@ class Brakeman::Warning
93
93
 
94
94
  #Generates a hash suitable for inserting into a Ruport table
95
95
  def to_row type = :warning
96
- return @row if @row
97
-
98
96
  @row = { "Confidence" => self.confidence,
99
97
  "Warning Type" => self.warning_type.to_s,
100
98
  "Message" => self.format_message }
@@ -122,4 +120,35 @@ class Brakeman::Warning
122
120
 
123
121
  output
124
122
  end
123
+
124
+ def to_hash
125
+ case @warning_set
126
+ when :template
127
+ location = { :type => :template, :template => self.view_name }
128
+ when :model
129
+ location = { :type => :model, :model => self.model }
130
+ when :controller
131
+ location = { :type => :controller, :controller => self.controller }
132
+ when :warning
133
+ if self.class
134
+ location = { :type => :method, :class => self.class, :method => self.method }
135
+ else
136
+ location = nil
137
+ end
138
+ end
139
+
140
+ { :warning_type => self.warning_type,
141
+ :message => self.message,
142
+ :file => self.file,
143
+ :code => (@code && self.format_code),
144
+ :location => location,
145
+ :confidence => TEXT_CONFIDENCE[self.confidence]
146
+ }
147
+ end
148
+
149
+ def to_json
150
+ require 'json'
151
+
152
+ JSON.dump self.to_hash
153
+ end
125
154
  end
metadata CHANGED
@@ -1,134 +1,101 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: brakeman
3
- version: !ruby/object:Gem::Version
4
- hash: 27
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.4.0
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 3
9
- - 0
10
- version: 1.3.0
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Justin Collins
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-02-09 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2012-02-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: activesupport
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &78318730 !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 3
29
- segments:
30
- - 0
31
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
32
22
  type: :runtime
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
35
- name: i18n
36
23
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *78318730
25
+ - !ruby/object:Gem::Dependency
26
+ name: i18n
27
+ requirement: &78318500 !ruby/object:Gem::Requirement
38
28
  none: false
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- hash: 3
43
- segments:
44
- - 0
45
- version: "0"
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
46
33
  type: :runtime
47
- version_requirements: *id002
48
- - !ruby/object:Gem::Dependency
49
- name: ruby2ruby
50
34
  prerelease: false
51
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *78318500
36
+ - !ruby/object:Gem::Dependency
37
+ name: ruby2ruby
38
+ requirement: &78318250 !ruby/object:Gem::Requirement
52
39
  none: false
53
- requirements:
40
+ requirements:
54
41
  - - ~>
55
- - !ruby/object:Gem::Version
56
- hash: 11
57
- segments:
58
- - 1
59
- - 2
60
- version: "1.2"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.2'
61
44
  type: :runtime
62
- version_requirements: *id003
63
- - !ruby/object:Gem::Dependency
64
- name: ruport
65
45
  prerelease: false
66
- requirement: &id004 !ruby/object:Gem::Requirement
46
+ version_requirements: *78318250
47
+ - !ruby/object:Gem::Dependency
48
+ name: ruport
49
+ requirement: &78318000 !ruby/object:Gem::Requirement
67
50
  none: false
68
- requirements:
51
+ requirements:
69
52
  - - ~>
70
- - !ruby/object:Gem::Version
71
- hash: 3
72
- segments:
73
- - 1
74
- - 6
75
- version: "1.6"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
76
55
  type: :runtime
77
- version_requirements: *id004
78
- - !ruby/object:Gem::Dependency
79
- name: erubis
80
56
  prerelease: false
81
- requirement: &id005 !ruby/object:Gem::Requirement
57
+ version_requirements: *78318000
58
+ - !ruby/object:Gem::Dependency
59
+ name: erubis
60
+ requirement: &78317770 !ruby/object:Gem::Requirement
82
61
  none: false
83
- requirements:
62
+ requirements:
84
63
  - - ~>
85
- - !ruby/object:Gem::Version
86
- hash: 15
87
- segments:
88
- - 2
89
- - 6
90
- version: "2.6"
64
+ - !ruby/object:Gem::Version
65
+ version: '2.6'
91
66
  type: :runtime
92
- version_requirements: *id005
93
- - !ruby/object:Gem::Dependency
94
- name: haml
95
67
  prerelease: false
96
- requirement: &id006 !ruby/object:Gem::Requirement
68
+ version_requirements: *78317770
69
+ - !ruby/object:Gem::Dependency
70
+ name: haml
71
+ requirement: &78317540 !ruby/object:Gem::Requirement
97
72
  none: false
98
- requirements:
73
+ requirements:
99
74
  - - ~>
100
- - !ruby/object:Gem::Version
101
- hash: 7
102
- segments:
103
- - 3
104
- - 0
105
- version: "3.0"
75
+ - !ruby/object:Gem::Version
76
+ version: '3.0'
106
77
  type: :runtime
107
- version_requirements: *id006
108
- - !ruby/object:Gem::Dependency
109
- name: sass
110
78
  prerelease: false
111
- requirement: &id007 !ruby/object:Gem::Requirement
79
+ version_requirements: *78317540
80
+ - !ruby/object:Gem::Dependency
81
+ name: sass
82
+ requirement: &78317310 !ruby/object:Gem::Requirement
112
83
  none: false
113
- requirements:
84
+ requirements:
114
85
  - - ~>
115
- - !ruby/object:Gem::Version
116
- hash: 7
117
- segments:
118
- - 3
119
- - 0
120
- version: "3.0"
86
+ - !ruby/object:Gem::Version
87
+ version: '3.0'
121
88
  type: :runtime
122
- version_requirements: *id007
123
- description: Brakeman detects security vulnerabilities in Ruby on Rails applications via static analysis.
89
+ prerelease: false
90
+ version_requirements: *78317310
91
+ description: Brakeman detects security vulnerabilities in Ruby on Rails applications
92
+ via static analysis.
124
93
  email:
125
- executables:
94
+ executables:
126
95
  - brakeman
127
96
  extensions: []
128
-
129
97
  extra_rdoc_files: []
130
-
131
- files:
98
+ files:
132
99
  - bin/brakeman
133
100
  - WARNING_TYPES
134
101
  - FEATURES
@@ -184,6 +151,7 @@ files:
184
151
  - lib/brakeman/checks/check_execute.rb
185
152
  - lib/brakeman/checks/check_filter_skipping.rb
186
153
  - lib/brakeman/checks/check_mail_to.rb
154
+ - lib/brakeman/checks/check_link_to_href.rb
187
155
  - lib/brakeman/checks/base_check.rb
188
156
  - lib/brakeman/checks/check_file_access.rb
189
157
  - lib/brakeman/checks/check_response_splitting.rb
@@ -204,36 +172,26 @@ files:
204
172
  - lib/brakeman/format/style.css
205
173
  homepage: http://brakemanscanner.org
206
174
  licenses: []
207
-
208
175
  post_install_message:
209
176
  rdoc_options: []
210
-
211
- require_paths:
177
+ require_paths:
212
178
  - lib
213
- required_ruby_version: !ruby/object:Gem::Requirement
179
+ required_ruby_version: !ruby/object:Gem::Requirement
214
180
  none: false
215
- requirements:
216
- - - ">="
217
- - !ruby/object:Gem::Version
218
- hash: 3
219
- segments:
220
- - 0
221
- version: "0"
222
- required_rubygems_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ! '>='
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
223
186
  none: false
224
- requirements:
225
- - - ">="
226
- - !ruby/object:Gem::Version
227
- hash: 3
228
- segments:
229
- - 0
230
- version: "0"
187
+ requirements:
188
+ - - ! '>='
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
231
191
  requirements: []
232
-
233
192
  rubyforge_project:
234
193
  rubygems_version: 1.8.15
235
194
  signing_key:
236
195
  specification_version: 3
237
196
  summary: Security vulnerability scanner for Ruby on Rails.
238
197
  test_files: []
239
-