brakeman 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/FEATURES +16 -0
  2. data/README.md +112 -0
  3. data/WARNING_TYPES +69 -0
  4. data/bin/brakeman +266 -0
  5. data/lib/checks.rb +67 -0
  6. data/lib/checks/base_check.rb +338 -0
  7. data/lib/checks/check_cross_site_scripting.rb +216 -0
  8. data/lib/checks/check_default_routes.rb +29 -0
  9. data/lib/checks/check_evaluation.rb +29 -0
  10. data/lib/checks/check_execute.rb +110 -0
  11. data/lib/checks/check_file_access.rb +46 -0
  12. data/lib/checks/check_forgery_setting.rb +25 -0
  13. data/lib/checks/check_mass_assignment.rb +72 -0
  14. data/lib/checks/check_model_attributes.rb +36 -0
  15. data/lib/checks/check_redirect.rb +98 -0
  16. data/lib/checks/check_render.rb +65 -0
  17. data/lib/checks/check_send_file.rb +15 -0
  18. data/lib/checks/check_session_settings.rb +36 -0
  19. data/lib/checks/check_sql.rb +124 -0
  20. data/lib/checks/check_validation_regex.rb +60 -0
  21. data/lib/format/style.css +105 -0
  22. data/lib/processor.rb +83 -0
  23. data/lib/processors/alias_processor.rb +384 -0
  24. data/lib/processors/base_processor.rb +235 -0
  25. data/lib/processors/config_processor.rb +146 -0
  26. data/lib/processors/controller_alias_processor.rb +222 -0
  27. data/lib/processors/controller_processor.rb +175 -0
  28. data/lib/processors/erb_template_processor.rb +84 -0
  29. data/lib/processors/erubis_template_processor.rb +62 -0
  30. data/lib/processors/haml_template_processor.rb +115 -0
  31. data/lib/processors/lib/find_call.rb +176 -0
  32. data/lib/processors/lib/find_model_call.rb +39 -0
  33. data/lib/processors/lib/processor_helper.rb +36 -0
  34. data/lib/processors/lib/render_helper.rb +118 -0
  35. data/lib/processors/library_processor.rb +117 -0
  36. data/lib/processors/model_processor.rb +125 -0
  37. data/lib/processors/output_processor.rb +204 -0
  38. data/lib/processors/params_processor.rb +77 -0
  39. data/lib/processors/route_processor.rb +338 -0
  40. data/lib/processors/template_alias_processor.rb +86 -0
  41. data/lib/processors/template_processor.rb +55 -0
  42. data/lib/report.rb +628 -0
  43. data/lib/scanner.rb +232 -0
  44. data/lib/tracker.rb +144 -0
  45. data/lib/util.rb +141 -0
  46. data/lib/warning.rb +97 -0
  47. metadata +191 -0
@@ -0,0 +1,84 @@
1
+ require 'processors/template_processor'
2
+
3
+ #Processes ERB templates
4
+ #(those ending in .html.erb or .rthml).
5
+ class ErbTemplateProcessor < TemplateProcessor
6
+
7
+ #s(:call, TARGET, :method, s(:arglist))
8
+ def process_call exp
9
+ target = exp[1]
10
+ if sexp? target
11
+ target = process target
12
+ end
13
+ method = exp[2]
14
+
15
+ #_erbout is the default output variable for erb
16
+ if target and target[1] == :_erbout
17
+ if method == :concat
18
+ @inside_concat = true
19
+ args = exp[3] = process(exp[3])
20
+ @inside_concat = false
21
+
22
+ if args.length > 2
23
+ raise Exception.new("Did not expect more than a single argument to _erbout.concat")
24
+ end
25
+
26
+ args = args[1]
27
+
28
+ if args.node_type == :call and args[2] == :to_s #erb always calls to_s on output
29
+ args = args[1]
30
+ end
31
+
32
+ if args.node_type == :str #ignore plain strings
33
+ ignore
34
+ else
35
+ s = Sexp.new :output, args
36
+ s.line(exp.line)
37
+ @current_template[:outputs] << s
38
+ s
39
+ end
40
+ elsif method == :force_encoding
41
+ ignore
42
+ else
43
+ abort "Unrecognized action on _erbout: #{method}"
44
+ end
45
+ elsif target == nil and method == :render
46
+ exp[3] = process(exp[3])
47
+ make_render exp
48
+ else
49
+ args = exp[3] = process(exp[3])
50
+ call = Sexp.new :call, target, method, args
51
+ call.line(exp.line)
52
+ call
53
+ end
54
+ end
55
+
56
+ #Process block, removing irrelevant expressions
57
+ def process_block exp
58
+ exp.shift
59
+ if @inside_concat
60
+ @inside_concat = false
61
+ exp[0..-2].each do |e|
62
+ process e
63
+ end
64
+ @inside_concat = true
65
+ process exp[-1]
66
+ else
67
+ exp.map! do |e|
68
+ res = process e
69
+ if res.empty? or res == ignore
70
+ nil
71
+ elsif sexp? res and res.node_type == :lvar and res[1] == :_erbout
72
+ nil
73
+
74
+ else
75
+ res
76
+ end
77
+ end
78
+ block = Sexp.new(:rlist).concat(exp).compact
79
+ block.line(exp.line)
80
+ block
81
+ end
82
+ end
83
+
84
+ end
@@ -0,0 +1,62 @@
1
+ require 'processors/template_processor'
2
+
3
+ #Processes ERB templates using Erubis instead of erb.
4
+ class ErubisTemplateProcessor < TemplateProcessor
5
+
6
+ #s(:call, TARGET, :method, s(:arglist))
7
+ def process_call exp
8
+ target = exp[1]
9
+ if sexp? target
10
+ target = process target
11
+ end
12
+ method = exp[2]
13
+
14
+ #_buf is the default output variable for Erubis
15
+ if target and target[1] == :_buf
16
+ if method == :<<
17
+ args = exp[3][1] = process(exp[3][1])
18
+
19
+ if args.node_type == :call and args[2] == :to_s #just calling to_s on inner code
20
+ args = args[1]
21
+ end
22
+
23
+ if args.node_type == :str #ignore plain strings
24
+ ignore
25
+ else
26
+ s = Sexp.new :output, args
27
+ s.line(exp.line)
28
+ @current_template[:outputs] << s
29
+ s
30
+ end
31
+ elsif method == :to_s
32
+ ignore
33
+ else
34
+ abort "Unrecognized action on _buf: #{method}"
35
+ end
36
+ elsif target == nil and method == :render
37
+ exp[3] = process exp[3]
38
+ make_render exp
39
+ else
40
+ args = exp[3] = process(exp[3])
41
+ call = Sexp.new :call, target, method, args
42
+ call.line(exp.line)
43
+ call
44
+ end
45
+ end
46
+
47
+ #Process blocks, ignoring :ignore exps
48
+ def process_block exp
49
+ exp.shift
50
+ exp.map! do |e|
51
+ res = process e
52
+ if res.empty? or res == ignore
53
+ nil
54
+ else
55
+ res
56
+ end
57
+ end
58
+ block = Sexp.new(:rlist).concat(exp).compact
59
+ block.line(exp.line)
60
+ block
61
+ end
62
+ end
@@ -0,0 +1,115 @@
1
+ require 'processors/template_processor'
2
+
3
+ #Processes HAML templates.
4
+ class HamlTemplateProcessor < TemplateProcessor
5
+ HAML_FORMAT_METHOD = /format_script_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)/
6
+
7
+ #Processes call, looking for template output
8
+ def process_call exp
9
+ target = exp[1]
10
+ if sexp? target
11
+ target = process target
12
+ end
13
+
14
+ method = exp[2]
15
+
16
+ if (sexp? target and target[2] == :_hamlout) or target == :_hamlout
17
+ res = case method
18
+ when :adjust_tabs, :rstrip!
19
+ ignore
20
+ when :options
21
+ Sexp.new :call, :_hamlout, :options, exp[3]
22
+ when :buffer
23
+ Sexp.new :call, :_hamlout, :buffer, exp[3]
24
+ when :open_tag
25
+ Sexp.new(:tag, process(exp[3]))
26
+ else
27
+ arg = exp[3][1]
28
+
29
+ if arg
30
+ @inside_concat = true
31
+ out = exp[3][1] = process(arg)
32
+ @inside_concat = false
33
+ else
34
+ raise Exception.new("Empty _hamlout.#{method}()?")
35
+ end
36
+
37
+ if string? out
38
+ ignore
39
+ else
40
+ case method.to_s
41
+ when "push_text"
42
+ s = Sexp.new(:output, out)
43
+ @current_template[:outputs] << s
44
+ s
45
+ when HAML_FORMAT_METHOD
46
+ if $4 == "true"
47
+ Sexp.new :format_escaped, out
48
+ else
49
+ Sexp.new :format, out
50
+ end
51
+ else
52
+ raise Exception.new("Unrecognized action on _hamlout: #{method}")
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ res.line(exp.line)
59
+ res
60
+
61
+ #_hamlout.buffer <<
62
+ #This seems to be used rarely, but directly appends args to output buffer
63
+ elsif sexp? target and method == :<< and is_buffer_target? target
64
+ @inside_concat = true
65
+ out = exp[3][1] = process(exp[3][1])
66
+ @inside_concat = false
67
+
68
+ if out.node_type == :str #ignore plain strings
69
+ ignore
70
+ else
71
+ s = Sexp.new(:output, out)
72
+ @current_template[:outputs] << s
73
+ s.line(exp.line)
74
+ s
75
+ end
76
+ elsif target == nil and method == :render
77
+ #Process call to render()
78
+ exp[3] = process exp[3]
79
+ make_render exp
80
+ else
81
+ args = process exp[3]
82
+ call = Sexp.new :call, target, method, args
83
+ call.line(exp.line)
84
+ call
85
+ end
86
+ end
87
+
88
+ #If inside an output stream, only return the final expression
89
+ def process_block exp
90
+ exp.shift
91
+ if @inside_concat
92
+ @inside_concat = false
93
+ exp[0..-2].each do |e|
94
+ process e
95
+ end
96
+ @inside_concat = true
97
+ process exp[-1]
98
+ else
99
+ exp.map! do |e|
100
+ res = process e
101
+ if res.empty?
102
+ nil
103
+ else
104
+ res
105
+ end
106
+ end
107
+ Sexp.new(:rlist).concat(exp).compact
108
+ end
109
+ end
110
+
111
+ #Checks if the buffer is the target in a method call Sexp.
112
+ def is_buffer_target? exp
113
+ exp.node_type == :call and exp[1] == :_hamlout and exp[2] == :buffer
114
+ end
115
+ end
@@ -0,0 +1,176 @@
1
+ require 'processors/base_processor'
2
+
3
+ #Finds method calls matching the given target(s).
4
+ #
5
+ #Targets/methods can be:
6
+ #
7
+ # - nil: matches anything, including nothing
8
+ # - Empty array: matches nothing
9
+ # - Symbol: matches single target/method exactly
10
+ # - Array of symbols: matches against any of the symbols
11
+ # - Regular expression: matches the expression
12
+ # - Array of regular expressions: matches any of the expressions
13
+ #
14
+ #If a target is also the name of a class, methods called on instances
15
+ #of that class will also be matched, in a very limited way.
16
+ #(Any methods called on Klass.new, basically. More useful when used
17
+ #in conjunction with AliasProcessor.)
18
+ #
19
+ #Examples:
20
+ #
21
+ # #To find any uses of this class:
22
+ # FindCall.new :FindCall, nil
23
+ #
24
+ # #Find system calls without a target
25
+ # FindCall.new [], [:system, :exec, :syscall]
26
+ #
27
+ # #Find all calls to length(), no matter the target
28
+ # FindCall.new nil, :length
29
+ #
30
+ # #Find all calls to sub, sub!, gsub, or gsub!
31
+ # FindCall.new nil, /^g?sub!?$/
32
+ class FindCall < BaseProcessor
33
+
34
+ def initialize targets, methods
35
+ super(nil)
36
+ @calls = []
37
+ @find_targets = targets
38
+ @find_methods = methods
39
+ @current_class = nil
40
+ @current_method = nil
41
+ end
42
+
43
+ #Returns a list of results.
44
+ #
45
+ #A result looks like:
46
+ #
47
+ # s(:result, :ClassName, :method_name, s(:call, ...))
48
+ #
49
+ #or
50
+ #
51
+ # s(:result, :template_name, s(:call, ...))
52
+ def matches
53
+ @calls
54
+ end
55
+
56
+ #Process the given source. Provide either class and method being searched
57
+ #or the template. These names are used when reporting results.
58
+ #
59
+ #Use FindCall#matches to retrieve results.
60
+ def process_source exp, klass = nil, method = nil, template = nil
61
+ @current_class = klass
62
+ @current_method = method
63
+ @current_template = template
64
+ process exp
65
+ end
66
+
67
+ #Process body of method
68
+ def process_methdef exp
69
+ process exp[3]
70
+ end
71
+
72
+ #Process body of method
73
+ def process_selfdef exp
74
+ process exp[4]
75
+ end
76
+
77
+ #Process body of block
78
+ def process_rlist exp
79
+ exp[1..-1].each do |e|
80
+ process e
81
+ end
82
+
83
+ exp
84
+ end
85
+
86
+ #Look for matching calls and add them to results
87
+ def process_call exp
88
+ target = get_target exp[1]
89
+ method = exp[2]
90
+
91
+ process exp[3]
92
+
93
+ if match(@find_targets, target) and match(@find_methods, method)
94
+
95
+ if @current_template
96
+ @calls << Sexp.new(:result, @current_template, exp).line(exp.line)
97
+ else
98
+ @calls << Sexp.new(:result, @current_class, @current_method, exp).line(exp.line)
99
+ end
100
+ end
101
+
102
+ exp
103
+ end
104
+
105
+ #Process an assignment like a call
106
+ def process_attrasgn exp
107
+ process_call exp
108
+ end
109
+
110
+ private
111
+
112
+ #Gets the target of a call as a Symbol
113
+ #if possible
114
+ def get_target exp
115
+ if sexp? exp
116
+ case exp.node_type
117
+ when :ivar, :lvar, :const
118
+ exp[1]
119
+ when :true, :false
120
+ exp[0]
121
+ when :lit
122
+ exp[1]
123
+ when :colon2
124
+ class_name exp
125
+ else
126
+ exp
127
+ end
128
+ else
129
+ exp
130
+ end
131
+ end
132
+
133
+ #Checks if the search terms match the given item
134
+ def match search_terms, item
135
+ case search_terms
136
+ when Symbol
137
+ if search_terms == item
138
+ true
139
+ elsif sexp? item
140
+ is_instance_of? item, search_terms
141
+ else
142
+ false
143
+ end
144
+ when Enumerable
145
+ if search_terms.empty?
146
+ item == nil
147
+ else
148
+ search_terms.each do|term|
149
+ if match(term, item)
150
+ return true
151
+ end
152
+ end
153
+ false
154
+ end
155
+ when Regexp
156
+ search_terms.match item.to_s
157
+ when nil
158
+ true
159
+ else
160
+ raise "Cannot match #{search_terms} and #{item}"
161
+ end
162
+ end
163
+
164
+ #Checks if +item+ is an instance of +klass+ by looking for Klass.new
165
+ def is_instance_of? item, klass
166
+ if call? item
167
+ if sexp? item[1]
168
+ item[2] == :new and item[1].node_type == :const and item[1][1] == klass
169
+ else
170
+ item[2] == :new and item[1] == klass
171
+ end
172
+ else
173
+ false
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,39 @@
1
+ require 'processors/lib/find_call'
2
+
3
+ #This processor specifically looks for calls like
4
+ # User.active.human.find(:all, :conditions => ...)
5
+ class FindModelCall < FindCall
6
+
7
+ #Passes +targets+ to FindCall
8
+ def initialize targets
9
+ super(targets, /^(find.*|first|last|all)$/)
10
+ end
11
+
12
+ #Matches entire method chain as a target. This differs from
13
+ #FindCall#get_target, which only matches the first expression in the chain.
14
+ def get_target exp
15
+ if sexp? exp
16
+ case exp.node_type
17
+ when :ivar, :lvar, :const
18
+ exp[1]
19
+ when :true, :false
20
+ exp[0]
21
+ when :lit
22
+ exp[1]
23
+ when :colon2
24
+ class_name exp
25
+ when :call
26
+ t = get_target(exp[1])
27
+ if t and match(@find_targets, t)
28
+ t
29
+ else
30
+ process exp
31
+ end
32
+ else
33
+ process exp
34
+ end
35
+ else
36
+ exp
37
+ end
38
+ end
39
+ end