brakeman 0.0.2
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/FEATURES +16 -0
- data/README.md +112 -0
- data/WARNING_TYPES +69 -0
- data/bin/brakeman +266 -0
- data/lib/checks.rb +67 -0
- data/lib/checks/base_check.rb +338 -0
- data/lib/checks/check_cross_site_scripting.rb +216 -0
- data/lib/checks/check_default_routes.rb +29 -0
- data/lib/checks/check_evaluation.rb +29 -0
- data/lib/checks/check_execute.rb +110 -0
- data/lib/checks/check_file_access.rb +46 -0
- data/lib/checks/check_forgery_setting.rb +25 -0
- data/lib/checks/check_mass_assignment.rb +72 -0
- data/lib/checks/check_model_attributes.rb +36 -0
- data/lib/checks/check_redirect.rb +98 -0
- data/lib/checks/check_render.rb +65 -0
- data/lib/checks/check_send_file.rb +15 -0
- data/lib/checks/check_session_settings.rb +36 -0
- data/lib/checks/check_sql.rb +124 -0
- data/lib/checks/check_validation_regex.rb +60 -0
- data/lib/format/style.css +105 -0
- data/lib/processor.rb +83 -0
- data/lib/processors/alias_processor.rb +384 -0
- data/lib/processors/base_processor.rb +235 -0
- data/lib/processors/config_processor.rb +146 -0
- data/lib/processors/controller_alias_processor.rb +222 -0
- data/lib/processors/controller_processor.rb +175 -0
- data/lib/processors/erb_template_processor.rb +84 -0
- data/lib/processors/erubis_template_processor.rb +62 -0
- data/lib/processors/haml_template_processor.rb +115 -0
- data/lib/processors/lib/find_call.rb +176 -0
- data/lib/processors/lib/find_model_call.rb +39 -0
- data/lib/processors/lib/processor_helper.rb +36 -0
- data/lib/processors/lib/render_helper.rb +118 -0
- data/lib/processors/library_processor.rb +117 -0
- data/lib/processors/model_processor.rb +125 -0
- data/lib/processors/output_processor.rb +204 -0
- data/lib/processors/params_processor.rb +77 -0
- data/lib/processors/route_processor.rb +338 -0
- data/lib/processors/template_alias_processor.rb +86 -0
- data/lib/processors/template_processor.rb +55 -0
- data/lib/report.rb +628 -0
- data/lib/scanner.rb +232 -0
- data/lib/tracker.rb +144 -0
- data/lib/util.rb +141 -0
- data/lib/warning.rb +97 -0
- metadata +191 -0
data/lib/checks.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
#Collects up results from running different checks.
|
2
|
+
#
|
3
|
+
#Checks can be added with +Check.add(check_class)+
|
4
|
+
#
|
5
|
+
#All .rb files in checks/ will be loaded.
|
6
|
+
class Checks
|
7
|
+
@checks = []
|
8
|
+
|
9
|
+
attr_reader :warnings, :controller_warnings, :model_warnings, :template_warnings, :checks_run
|
10
|
+
|
11
|
+
#Add a check. This will call +_klass_.new+ when running tests
|
12
|
+
def self.add klass
|
13
|
+
@checks << klass
|
14
|
+
end
|
15
|
+
|
16
|
+
#No need to use this directly.
|
17
|
+
def initialize
|
18
|
+
@warnings = []
|
19
|
+
@template_warnings = []
|
20
|
+
@model_warnings = []
|
21
|
+
@controller_warnings = []
|
22
|
+
@checks_run = []
|
23
|
+
end
|
24
|
+
|
25
|
+
#Add Warning to list of warnings to report.
|
26
|
+
#Warnings are split into four different arrays
|
27
|
+
#for template, controller, model, and generic warnings.
|
28
|
+
def add_warning warning
|
29
|
+
case warning.warning_set
|
30
|
+
when :template
|
31
|
+
@template_warnings << warning
|
32
|
+
when :warning
|
33
|
+
@warnings << warning
|
34
|
+
when :controller
|
35
|
+
@controller_warnings << warning
|
36
|
+
when :model
|
37
|
+
@model_warnings << warning
|
38
|
+
else
|
39
|
+
raise "Unknown warning: #{warning.warning_set}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#Run all the checks on the given Tracker.
|
44
|
+
#Returns a new instance of Checks with the results.
|
45
|
+
def self.run_checks tracker
|
46
|
+
checks = self.new
|
47
|
+
@checks.each do |c|
|
48
|
+
#Run or don't run check based on options
|
49
|
+
unless OPTIONS[:skip_checks].include? c.to_s or
|
50
|
+
(OPTIONS[:run_checks] and not OPTIONS[:run_checks].include? c.to_s)
|
51
|
+
|
52
|
+
warn " - #{c}"
|
53
|
+
c.new(checks, tracker).run_check
|
54
|
+
|
55
|
+
#Maintain list of which checks were run
|
56
|
+
#mainly for reporting purposes
|
57
|
+
checks.checks_run << c.to_s[5..-1]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
checks
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
#Load all files in checks/ directory
|
65
|
+
Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/checks/*.rb").sort.each do |f|
|
66
|
+
require f.match(/(checks\/.*)\.rb$/)[0]
|
67
|
+
end
|
@@ -0,0 +1,338 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sexp_processor'
|
3
|
+
require 'processors/output_processor'
|
4
|
+
require 'warning'
|
5
|
+
require 'util'
|
6
|
+
|
7
|
+
#Basis of vulnerability checks.
|
8
|
+
class BaseCheck < SexpProcessor
|
9
|
+
include ProcessorHelper
|
10
|
+
include Util
|
11
|
+
attr_reader :checks, :tracker
|
12
|
+
|
13
|
+
CONFIDENCE = { :high => 0, :med => 1, :low => 2 }
|
14
|
+
|
15
|
+
#Initialize Check with Checks.
|
16
|
+
def initialize checks, tracker
|
17
|
+
super()
|
18
|
+
@results = [] #only to check for duplicates
|
19
|
+
@checks = checks
|
20
|
+
@tracker = tracker
|
21
|
+
@string_interp = false
|
22
|
+
@current_template = @current_module = @current_class = @current_method = nil
|
23
|
+
self.strict = false
|
24
|
+
self.auto_shift_type = false
|
25
|
+
self.require_empty = false
|
26
|
+
self.default_method = :process_default
|
27
|
+
self.warn_on_default = false
|
28
|
+
end
|
29
|
+
|
30
|
+
#Add result to result list, which is used to check for duplicates
|
31
|
+
def add_result result, location = nil
|
32
|
+
location ||= (@current_template && @current_template[:name]) || @current_class || @current_module || @current_set || result[1]
|
33
|
+
location = location[:name] if location.is_a? Hash
|
34
|
+
location = location.to_sym
|
35
|
+
|
36
|
+
@results << [result.line, location, result]
|
37
|
+
end
|
38
|
+
|
39
|
+
#Default Sexp processing. Iterates over each value in the Sexp
|
40
|
+
#and processes them if they are also Sexps.
|
41
|
+
def process_default exp
|
42
|
+
type = exp.shift
|
43
|
+
exp.each_with_index do |e, i|
|
44
|
+
if sexp? e
|
45
|
+
process e
|
46
|
+
else
|
47
|
+
e
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
exp.unshift type
|
52
|
+
end
|
53
|
+
|
54
|
+
#Process calls and check if they include user input
|
55
|
+
def process_call exp
|
56
|
+
process exp[1] if sexp? exp[1]
|
57
|
+
process exp[3]
|
58
|
+
|
59
|
+
if ALL_PARAMETERS.include? exp[1] or ALL_PARAMETERS.include? exp or params? exp[1]
|
60
|
+
@has_user_input = :params
|
61
|
+
elsif exp[1] == COOKIES or exp == COOKIES or cookies? exp[1]
|
62
|
+
@has_user_input = :cookies
|
63
|
+
elsif sexp? exp[1] and model_name? exp[1][1]
|
64
|
+
@has_user_input = :model
|
65
|
+
end
|
66
|
+
|
67
|
+
exp
|
68
|
+
end
|
69
|
+
|
70
|
+
#Note that params are included in current expression
|
71
|
+
def process_params exp
|
72
|
+
@has_user_input = :params
|
73
|
+
exp
|
74
|
+
end
|
75
|
+
|
76
|
+
#Note that cookies are included in current expression
|
77
|
+
def process_cookies exp
|
78
|
+
@has_user_input = :cookies
|
79
|
+
exp
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
#Report a warning
|
85
|
+
def warn options
|
86
|
+
@checks.add_warning Warning.new(options.merge({ :check => self.class.to_s }))
|
87
|
+
end
|
88
|
+
|
89
|
+
#Run _exp_ through OutputProcessor to get a nice String.
|
90
|
+
def format_output exp
|
91
|
+
OutputProcessor.new.format(exp).gsub(/\r|\n/, "")
|
92
|
+
end
|
93
|
+
|
94
|
+
#Checks if the model inherits from parent,
|
95
|
+
def parent? tracker, model, parent
|
96
|
+
if model == nil
|
97
|
+
false
|
98
|
+
elsif model[:parent] == parent
|
99
|
+
true
|
100
|
+
elsif model[:parent]
|
101
|
+
parent? tracker, tracker.models[model[:parent]], parent
|
102
|
+
else
|
103
|
+
false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
#Checks if mass assignment is disabled globally in an initializer.
|
108
|
+
def mass_assign_disabled? tracker
|
109
|
+
matches = tracker.check_initializers(:"ActiveRecord::Base", :send)
|
110
|
+
if matches.empty?
|
111
|
+
false
|
112
|
+
else
|
113
|
+
matches.each do |result|
|
114
|
+
if result[3][3] == Sexp.new(:arg_list, Sexp.new(:lit, :attr_accessible), Sexp.new(:nil))
|
115
|
+
return true
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
#This is to avoid reporting duplicates. Checks if the result has been
|
122
|
+
#reported already from the same line number.
|
123
|
+
def duplicate? result, location = nil
|
124
|
+
line = result.line
|
125
|
+
location ||= (@current_template && @current_template[:name]) || @current_class || @current_module || @current_set || result[1]
|
126
|
+
|
127
|
+
location = location[:name] if location.is_a? Hash
|
128
|
+
location = location.to_sym
|
129
|
+
@results.each do |r|
|
130
|
+
if r[0] == line and r[1] == location
|
131
|
+
if OPTIONS[:combine_locations]
|
132
|
+
return true
|
133
|
+
elsif r[2] == result
|
134
|
+
return true
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
false
|
140
|
+
end
|
141
|
+
|
142
|
+
#Ignores ignores
|
143
|
+
def process_ignore exp
|
144
|
+
exp
|
145
|
+
end
|
146
|
+
|
147
|
+
#Does not actually process string interpolation, but notes that it occurred.
|
148
|
+
def process_string_interp exp
|
149
|
+
@string_interp = true
|
150
|
+
exp
|
151
|
+
end
|
152
|
+
|
153
|
+
#Checks if an expression contains string interpolation.
|
154
|
+
def include_interp? exp
|
155
|
+
@string_interp = false
|
156
|
+
process exp
|
157
|
+
@string_interp
|
158
|
+
end
|
159
|
+
|
160
|
+
#Checks if _exp_ includes parameters or cookies, but this only works
|
161
|
+
#with the base process_default.
|
162
|
+
def include_user_input? exp
|
163
|
+
@has_user_input = false
|
164
|
+
process exp
|
165
|
+
@has_user_input
|
166
|
+
end
|
167
|
+
|
168
|
+
#This is used to check for user input being used directly.
|
169
|
+
#
|
170
|
+
#Returns false if none is found, otherwise it returns an array
|
171
|
+
#where the first element is the type of user input
|
172
|
+
#(either :params or :cookies) and the second element is the matching
|
173
|
+
#expression
|
174
|
+
def has_immediate_user_input? exp
|
175
|
+
if params? exp
|
176
|
+
return :params, exp
|
177
|
+
elsif cookies? exp
|
178
|
+
return :cookies, exp
|
179
|
+
elsif call? exp
|
180
|
+
if sexp? exp[1]
|
181
|
+
if ALL_PARAMETERS.include? exp[1] or params? exp[1]
|
182
|
+
return :params, exp
|
183
|
+
elsif exp[1] == COOKIES
|
184
|
+
return :cookies, exp
|
185
|
+
else
|
186
|
+
false
|
187
|
+
end
|
188
|
+
else
|
189
|
+
false
|
190
|
+
end
|
191
|
+
elsif sexp? exp
|
192
|
+
case exp.node_type
|
193
|
+
when :string_interp
|
194
|
+
exp.each do |e|
|
195
|
+
if sexp? e
|
196
|
+
type, match = has_immediate_user_input?(e)
|
197
|
+
if type
|
198
|
+
return type, match
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
false
|
203
|
+
when :string_eval
|
204
|
+
if sexp? exp[1]
|
205
|
+
if exp[1].node_type == :rlist
|
206
|
+
exp[1].each do |e|
|
207
|
+
if sexp? e
|
208
|
+
type, match = has_immediate_user_input?(e)
|
209
|
+
if type
|
210
|
+
return type, match
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
false
|
215
|
+
else
|
216
|
+
has_immediate_user_input? exp[1]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
when :format
|
220
|
+
has_immediate_user_input? exp[1]
|
221
|
+
when :if
|
222
|
+
(sexp? exp[2] and has_immediate_user_input? exp[2]) or
|
223
|
+
(sexp? exp[3] and has_immediate_user_input? exp[3])
|
224
|
+
else
|
225
|
+
false
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
#Checks for a model attribute at the top level of the
|
231
|
+
#expression.
|
232
|
+
def has_immediate_model? exp, out = nil
|
233
|
+
out = exp if out.nil?
|
234
|
+
|
235
|
+
if sexp? exp and exp.node_type == :output
|
236
|
+
exp = exp[1]
|
237
|
+
end
|
238
|
+
|
239
|
+
if call? exp
|
240
|
+
target = exp[1]
|
241
|
+
method = exp[2]
|
242
|
+
|
243
|
+
if call? target and not method.to_s[-1,1] == "?"
|
244
|
+
has_immediate_model? target, out
|
245
|
+
elsif model_name? target
|
246
|
+
exp
|
247
|
+
else
|
248
|
+
false
|
249
|
+
end
|
250
|
+
elsif sexp? exp
|
251
|
+
case exp.node_type
|
252
|
+
when :string_interp
|
253
|
+
exp.each do |e|
|
254
|
+
if sexp? e and match = has_immediate_model?(e, out)
|
255
|
+
return match
|
256
|
+
end
|
257
|
+
end
|
258
|
+
false
|
259
|
+
when :string_eval
|
260
|
+
if sexp? exp[1]
|
261
|
+
if exp[1].node_type == :rlist
|
262
|
+
exp[1].each do |e|
|
263
|
+
if sexp? e and match = has_immediate_model?(e, out)
|
264
|
+
return match
|
265
|
+
end
|
266
|
+
end
|
267
|
+
false
|
268
|
+
else
|
269
|
+
has_immediate_model? exp[1], out
|
270
|
+
end
|
271
|
+
end
|
272
|
+
when :format
|
273
|
+
has_immediate_model? exp[1], out
|
274
|
+
when :if
|
275
|
+
((sexp? exp[2] and has_immediate_model? exp[2], out) or
|
276
|
+
(sexp? exp[3] and has_immediate_model? exp[3], out))
|
277
|
+
else
|
278
|
+
false
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
#Checks if +exp+ is a model name.
|
284
|
+
#
|
285
|
+
#Prior to using this method, either @tracker must be set to
|
286
|
+
#the current tracker, or else @models should contain an array of the model
|
287
|
+
#names, which is available via tracker.models.keys
|
288
|
+
def model_name? exp
|
289
|
+
@models ||= @tracker.models.keys
|
290
|
+
|
291
|
+
if exp.is_a? Symbol
|
292
|
+
@models.include? exp
|
293
|
+
elsif sexp? exp
|
294
|
+
klass = nil
|
295
|
+
begin
|
296
|
+
klass = class_name exp
|
297
|
+
rescue StandardError
|
298
|
+
end
|
299
|
+
|
300
|
+
klass and @models.include? klass
|
301
|
+
else
|
302
|
+
false
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
#Finds entire method call chain where +target+ is a target in the chain
|
307
|
+
def find_chain exp, target
|
308
|
+
return unless sexp? exp
|
309
|
+
|
310
|
+
case exp.node_type
|
311
|
+
when :output, :format
|
312
|
+
find_chain exp[1], target
|
313
|
+
when :call
|
314
|
+
if exp == target or include_target? exp, target
|
315
|
+
return exp
|
316
|
+
end
|
317
|
+
else
|
318
|
+
exp.each do |e|
|
319
|
+
if sexp? e
|
320
|
+
res = find_chain e, target
|
321
|
+
return res if res
|
322
|
+
end
|
323
|
+
end
|
324
|
+
nil
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
#Returns true if +target+ is in +exp+
|
329
|
+
def include_target? exp, target
|
330
|
+
return false unless call? exp
|
331
|
+
|
332
|
+
exp.each do |e|
|
333
|
+
return true if e == target or include_target? e, target
|
334
|
+
end
|
335
|
+
|
336
|
+
false
|
337
|
+
end
|
338
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'checks/base_check'
|
2
|
+
require 'processors/lib/find_call'
|
3
|
+
require 'processors/lib/processor_helper'
|
4
|
+
require 'util'
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
#This check looks for unescaped output in templates which contains
|
8
|
+
#parameters or model attributes.
|
9
|
+
#
|
10
|
+
#For example:
|
11
|
+
#
|
12
|
+
# <%= User.find(:id).name %>
|
13
|
+
# <%= params[:id] %>
|
14
|
+
class CheckCrossSiteScripting < BaseCheck
|
15
|
+
Checks.add self
|
16
|
+
|
17
|
+
#Ignore these methods and their arguments.
|
18
|
+
#It is assumed they will take care of escaping their output.
|
19
|
+
IGNORE_METHODS = Set.new([:h, :escapeHTML, :link_to, :text_field_tag, :hidden_field_tag,
|
20
|
+
:image_tag, :select, :submit_tag, :hidden_field, :url_encode,
|
21
|
+
:radio_button, :will_paginate, :button_to, :url_for, :mail_to,
|
22
|
+
:fields_for, :label, :text_area, :text_field, :hidden_field, :check_box,
|
23
|
+
:field_field])
|
24
|
+
|
25
|
+
IGNORE_MODEL_METHODS = Set.new([:average, :count, :maximum, :minimum, :sum])
|
26
|
+
|
27
|
+
MODEL_METHODS = Set.new([:all, :find, :first, :last, :new])
|
28
|
+
|
29
|
+
IGNORE_LIKE = /^link_to_|_path|_tag|_url$/
|
30
|
+
|
31
|
+
HAML_HELPERS = Sexp.new(:colon2, Sexp.new(:const, :Haml), :Helpers)
|
32
|
+
|
33
|
+
URI = Sexp.new(:const, :URI)
|
34
|
+
|
35
|
+
CGI = Sexp.new(:const, :CGI)
|
36
|
+
|
37
|
+
FORM_BUILDER = Sexp.new(:call, Sexp.new(:const, :FormBuilder), :new, Sexp.new(:arglist))
|
38
|
+
|
39
|
+
#Run check
|
40
|
+
def run_check
|
41
|
+
IGNORE_METHODS.merge OPTIONS[:safe_methods]
|
42
|
+
@models = tracker.models.keys
|
43
|
+
@inspect_arguments = OPTIONS[:check_arguments]
|
44
|
+
|
45
|
+
tracker.each_template do |name, template|
|
46
|
+
@current_template = template
|
47
|
+
|
48
|
+
template[:outputs].each do |out|
|
49
|
+
type, match = has_immediate_user_input?(out[1])
|
50
|
+
if type
|
51
|
+
unless duplicate? out
|
52
|
+
add_result out
|
53
|
+
case type
|
54
|
+
when :params
|
55
|
+
|
56
|
+
warn :template => @current_template,
|
57
|
+
:warning_type => "Cross Site Scripting",
|
58
|
+
:message => "Unescaped parameter value",
|
59
|
+
:line => match.line,
|
60
|
+
:code => match,
|
61
|
+
:confidence => CONFIDENCE[:high]
|
62
|
+
|
63
|
+
when :cookies
|
64
|
+
|
65
|
+
warn :template => @current_template,
|
66
|
+
:warning_type => "Cross Site Scripting",
|
67
|
+
:message => "Unescaped cookie value",
|
68
|
+
:line => match.line,
|
69
|
+
:code => match,
|
70
|
+
:confidence => CONFIDENCE[:high]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
elsif not OPTIONS[:ignore_model_output] and match = has_immediate_model?(out[1])
|
74
|
+
method = match[2]
|
75
|
+
|
76
|
+
unless duplicate? out or IGNORE_MODEL_METHODS.include? method
|
77
|
+
add_result out
|
78
|
+
|
79
|
+
if MODEL_METHODS.include? method or method.to_s =~ /^find_by/
|
80
|
+
confidence = CONFIDENCE[:high]
|
81
|
+
else
|
82
|
+
confidence = CONFIDENCE[:med]
|
83
|
+
end
|
84
|
+
|
85
|
+
code = find_chain out, match
|
86
|
+
warn :template => @current_template,
|
87
|
+
:warning_type => "Cross Site Scripting",
|
88
|
+
:message => "Unescaped model attribute",
|
89
|
+
:line => code.line,
|
90
|
+
:code => code,
|
91
|
+
:confidence => confidence
|
92
|
+
end
|
93
|
+
|
94
|
+
else
|
95
|
+
@matched = false
|
96
|
+
@mark = false
|
97
|
+
process out
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
#Process an output Sexp
|
104
|
+
def process_output exp
|
105
|
+
process exp[1]
|
106
|
+
end
|
107
|
+
|
108
|
+
#Check a call for user input
|
109
|
+
#
|
110
|
+
#
|
111
|
+
#Since we want to report an entire call and not just part of one, use @mark
|
112
|
+
#to mark when a call is started. Any dangerous values inside will then
|
113
|
+
#report the entire call chain.
|
114
|
+
def process_call exp
|
115
|
+
if @mark
|
116
|
+
actually_process_call exp
|
117
|
+
else
|
118
|
+
@mark = true
|
119
|
+
actually_process_call exp
|
120
|
+
message = nil
|
121
|
+
|
122
|
+
if @matched == :model and not OPTIONS[:ignore_model_output]
|
123
|
+
message = "Unescaped model attribute"
|
124
|
+
elsif @matched == :params
|
125
|
+
message = "Unescaped parameter value"
|
126
|
+
end
|
127
|
+
|
128
|
+
if message and not duplicate? exp
|
129
|
+
add_result exp
|
130
|
+
|
131
|
+
warn :template => @current_template,
|
132
|
+
:warning_type => "Cross Site Scripting",
|
133
|
+
:message => message,
|
134
|
+
:line => exp.line,
|
135
|
+
:code => exp,
|
136
|
+
:confidence => CONFIDENCE[:low]
|
137
|
+
end
|
138
|
+
|
139
|
+
@mark = @matched = false
|
140
|
+
end
|
141
|
+
|
142
|
+
exp
|
143
|
+
end
|
144
|
+
|
145
|
+
def actually_process_call exp
|
146
|
+
return if @matched
|
147
|
+
target = exp[1]
|
148
|
+
if sexp? target
|
149
|
+
target = process target
|
150
|
+
end
|
151
|
+
|
152
|
+
method = exp[2]
|
153
|
+
args = exp[3]
|
154
|
+
|
155
|
+
#Ignore safe items
|
156
|
+
if (target.nil? and (IGNORE_METHODS.include? method or method.to_s =~ IGNORE_LIKE)) or
|
157
|
+
(@matched == :model and IGNORE_MODEL_METHODS.include? method) or
|
158
|
+
(target == HAML_HELPERS and method == :html_escape) or
|
159
|
+
((target == URI or target == CGI) and method == :escape) or
|
160
|
+
(target == FORM_BUILDER and IGNORE_METHODS.include? method) or
|
161
|
+
(method.to_s[-1,1] == "?")
|
162
|
+
|
163
|
+
exp[0] = :ignore
|
164
|
+
@matched = false
|
165
|
+
elsif sexp? exp[1] and model_name? exp[1][1]
|
166
|
+
|
167
|
+
@matched = :model
|
168
|
+
elsif @inspect_arguments and (ALL_PARAMETERS.include?(exp) or params? exp)
|
169
|
+
|
170
|
+
@matched = :params
|
171
|
+
else
|
172
|
+
process args if @inspect_arguments
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
#Note that params have been found
|
177
|
+
def process_params exp
|
178
|
+
@matched = :params
|
179
|
+
exp
|
180
|
+
end
|
181
|
+
|
182
|
+
#Note that cookies have been found
|
183
|
+
def process_cookies exp
|
184
|
+
@matched = :cookies
|
185
|
+
exp
|
186
|
+
end
|
187
|
+
|
188
|
+
#Ignore calls to render
|
189
|
+
def process_render exp
|
190
|
+
exp
|
191
|
+
end
|
192
|
+
|
193
|
+
#Process as default
|
194
|
+
def process_string_interp exp
|
195
|
+
process_default exp
|
196
|
+
end
|
197
|
+
|
198
|
+
#Process as default
|
199
|
+
def process_format exp
|
200
|
+
process_default exp
|
201
|
+
end
|
202
|
+
|
203
|
+
#Ignore output HTML escaped via HAML
|
204
|
+
def process_format_escaped exp
|
205
|
+
exp
|
206
|
+
end
|
207
|
+
|
208
|
+
#Ignore condition in if Sexp
|
209
|
+
def process_if exp
|
210
|
+
exp[2..-1].each do |e|
|
211
|
+
process e if sexp? e
|
212
|
+
end
|
213
|
+
exp
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|