brakeman-lib 4.5.1 → 4.7.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.
- checksums.yaml +4 -4
- data/CHANGES.md +158 -109
- data/README.md +1 -2
- data/lib/brakeman/call_index.rb +54 -15
- data/lib/brakeman/checks/base_check.rb +50 -47
- data/lib/brakeman/checks/check_cookie_serialization.rb +22 -0
- data/lib/brakeman/checks/check_cross_site_scripting.rb +4 -4
- data/lib/brakeman/checks/check_deserialize.rb +3 -6
- data/lib/brakeman/checks/check_execute.rb +26 -1
- data/lib/brakeman/checks/check_file_access.rb +7 -1
- data/lib/brakeman/checks/check_header_dos.rb +2 -2
- data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
- data/lib/brakeman/checks/check_jruby_xml.rb +2 -2
- data/lib/brakeman/checks/check_json_parsing.rb +2 -2
- data/lib/brakeman/checks/check_mass_assignment.rb +1 -1
- data/lib/brakeman/checks/check_mime_type_dos.rb +2 -2
- data/lib/brakeman/checks/check_nested_attributes_bypass.rb +1 -1
- data/lib/brakeman/checks/check_reverse_tabnabbing.rb +58 -0
- data/lib/brakeman/checks/check_sanitize_methods.rb +2 -2
- data/lib/brakeman/checks/check_session_settings.rb +5 -2
- data/lib/brakeman/checks/check_sql.rb +24 -22
- data/lib/brakeman/checks/check_xml_dos.rb +2 -2
- data/lib/brakeman/checks/check_yaml_parsing.rb +10 -18
- data/lib/brakeman/differ.rb +16 -28
- data/lib/brakeman/file_parser.rb +4 -8
- data/lib/brakeman/file_path.rb +14 -0
- data/lib/brakeman/parsers/haml_embedded.rb +1 -1
- data/lib/brakeman/parsers/template_parser.rb +3 -1
- data/lib/brakeman/processor.rb +2 -2
- data/lib/brakeman/processors/alias_processor.rb +15 -1
- data/lib/brakeman/processors/base_processor.rb +2 -0
- data/lib/brakeman/processors/controller_processor.rb +4 -4
- data/lib/brakeman/processors/gem_processor.rb +10 -2
- data/lib/brakeman/processors/haml_template_processor.rb +87 -123
- data/lib/brakeman/processors/lib/call_conversion_helper.rb +5 -4
- data/lib/brakeman/processors/lib/find_all_calls.rb +27 -4
- data/lib/brakeman/processors/lib/find_call.rb +3 -64
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +1 -1
- data/lib/brakeman/processors/template_alias_processor.rb +28 -0
- data/lib/brakeman/processors/template_processor.rb +10 -6
- data/lib/brakeman/report/report_text.rb +4 -5
- data/lib/brakeman/rescanner.rb +4 -0
- data/lib/brakeman/tracker.rb +26 -2
- data/lib/brakeman/tracker/config.rb +38 -73
- data/lib/brakeman/tracker/constants.rb +2 -1
- data/lib/brakeman/util.rb +5 -3
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +4 -0
- data/lib/brakeman/warning_codes.rb +3 -0
- data/lib/ruby_parser/bm_sexp.rb +7 -2
- metadata +18 -17
@@ -79,7 +79,9 @@ module Brakeman
|
|
79
79
|
|
80
80
|
Haml::Engine.new(text,
|
81
81
|
:filename => path,
|
82
|
-
:escape_html => tracker.config.escape_html
|
82
|
+
:escape_html => tracker.config.escape_html?,
|
83
|
+
:escape_filter_interpolations => tracker.config.escape_filter_interpolations?
|
84
|
+
).precompiled.gsub(/([^\\])\\n/, '\1')
|
83
85
|
rescue Haml::Error => e
|
84
86
|
tracker.error e, ["While compiling HAML in #{path}"] << e.backtrace
|
85
87
|
nil
|
data/lib/brakeman/processor.rb
CHANGED
@@ -53,7 +53,7 @@ module Brakeman
|
|
53
53
|
#Process a model source
|
54
54
|
def process_model src, file_name
|
55
55
|
result = ModelProcessor.new(@tracker).process_model src, file_name
|
56
|
-
AliasProcessor.new(@tracker).process result if result
|
56
|
+
AliasProcessor.new(@tracker, file_name).process result if result
|
57
57
|
end
|
58
58
|
|
59
59
|
#Process either an ERB or HAML template
|
@@ -90,7 +90,7 @@ module Brakeman
|
|
90
90
|
def process_initializer file_name, src
|
91
91
|
res = BaseProcessor.new(@tracker).process_file src, file_name
|
92
92
|
res = AliasProcessor.new(@tracker).process_safely res, nil, file_name
|
93
|
-
@tracker.initializers[
|
93
|
+
@tracker.initializers[file_name] = res
|
94
94
|
end
|
95
95
|
|
96
96
|
#Process source for a library file
|
@@ -249,6 +249,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
249
249
|
end
|
250
250
|
env[target_var] = target
|
251
251
|
return first_arg
|
252
|
+
elsif new_string? target
|
253
|
+
env[target_var] = first_arg
|
254
|
+
return first_arg
|
252
255
|
elsif array? target
|
253
256
|
target << first_arg
|
254
257
|
env[target_var] = target
|
@@ -265,6 +268,10 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
265
268
|
unless target.nil?
|
266
269
|
exp = target
|
267
270
|
end
|
271
|
+
when :dup
|
272
|
+
unless target.nil?
|
273
|
+
exp = target
|
274
|
+
end
|
268
275
|
when :join
|
269
276
|
if array? target and target.length > 2 and (string? first_arg or first_arg.nil?)
|
270
277
|
exp = process_array_join(target, first_arg)
|
@@ -602,7 +609,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
602
609
|
if node_type? exp, :hash
|
603
610
|
if exp.any? { |e| node_type? e, :kwsplat and node_type? e.value, :hash }
|
604
611
|
kwsplats, rest = exp.partition { |e| node_type? e, :kwsplat and node_type? e.value, :hash }
|
605
|
-
exp = Sexp.new.concat(rest).line(exp)
|
612
|
+
exp = Sexp.new.concat(rest).line(exp.line)
|
606
613
|
|
607
614
|
kwsplats.each do |e|
|
608
615
|
exp = process_hash_merge! exp, e.value
|
@@ -1194,6 +1201,13 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
1194
1201
|
call? exp and exp.method == :raise
|
1195
1202
|
end
|
1196
1203
|
|
1204
|
+
STRING_NEW = s(:call, s(:const, :String), :new)
|
1205
|
+
|
1206
|
+
# String.new ?
|
1207
|
+
def new_string? exp
|
1208
|
+
exp == STRING_NEW
|
1209
|
+
end
|
1210
|
+
|
1197
1211
|
#Set variable to given value.
|
1198
1212
|
#Creates "branched" versions of values when appropriate.
|
1199
1213
|
#Avoids creating multiple branched versions inside same
|
@@ -192,8 +192,8 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
|
|
192
192
|
|
193
193
|
filter_name = ("fake_filter" + rand.to_s[/\d+$/]).to_sym
|
194
194
|
args = exp.block_call.arglist
|
195
|
-
args.insert(1, Sexp.new(:lit, filter_name))
|
196
|
-
before_filter_call = make_call(nil, :before_filter, args)
|
195
|
+
args.insert(1, Sexp.new(:lit, filter_name).line(exp.line))
|
196
|
+
before_filter_call = make_call(nil, :before_filter, args).line(exp.line)
|
197
197
|
|
198
198
|
if exp.block_args.length > 1
|
199
199
|
block_variable = exp.block_args[1]
|
@@ -210,9 +210,9 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
|
|
210
210
|
#Build Sexp for filter method
|
211
211
|
body = Sexp.new(:lasgn,
|
212
212
|
block_variable,
|
213
|
-
Sexp.new(:call, Sexp.new(:const, @current_class.name), :new))
|
213
|
+
Sexp.new(:call, Sexp.new(:const, @current_class.name).line(exp.line), :new).line(exp.line)).line(exp.line)
|
214
214
|
|
215
|
-
filter_method = Sexp.new(:defn, filter_name, Sexp.new(:args), body).concat(block_inner).line(exp.line)
|
215
|
+
filter_method = Sexp.new(:defn, filter_name, Sexp.new(:args).line(exp.line), body).concat(block_inner).line(exp.line)
|
216
216
|
|
217
217
|
vis = @visibility
|
218
218
|
@visibility = :private
|
@@ -29,6 +29,14 @@ class Brakeman::GemProcessor < Brakeman::BasicProcessor
|
|
29
29
|
@tracker.config.set_rails_version
|
30
30
|
end
|
31
31
|
|
32
|
+
# Known issue: Brakeman does not yet support `gem` calls with multiple
|
33
|
+
# "version requirements". Consider the following example from the ruby docs:
|
34
|
+
#
|
35
|
+
# gem 'rake', '>= 1.1.a', '< 2'
|
36
|
+
#
|
37
|
+
# We are assuming that `second_arg` (eg. '>= 1.1.a') is the only requirement.
|
38
|
+
# Perhaps we should instantiate an array of `::Gem::Requirement`s or even a
|
39
|
+
# `::Gem::Dependency` and pass that to `Tracker::Config#add_gem`?
|
32
40
|
def process_call exp
|
33
41
|
if exp.target == nil
|
34
42
|
if exp.method == :gem
|
@@ -51,8 +59,8 @@ class Brakeman::GemProcessor < Brakeman::BasicProcessor
|
|
51
59
|
end
|
52
60
|
end
|
53
61
|
elsif @inside_gemspec and exp.method == :add_dependency
|
54
|
-
if string? exp.first_arg and string? exp.
|
55
|
-
@tracker.config.add_gem exp.first_arg.value, exp.
|
62
|
+
if string? exp.first_arg and string? exp.second_arg
|
63
|
+
@tracker.config.add_gem exp.first_arg.value, exp.second_arg.value, @gemspec, exp.line
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
@@ -2,8 +2,10 @@ require 'brakeman/processors/template_processor'
|
|
2
2
|
|
3
3
|
#Processes HAML templates.
|
4
4
|
class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
5
|
-
|
5
|
+
HAMLOUT = s(:call, nil, :_hamlout)
|
6
|
+
HAML_BUFFER = s(:call, HAMLOUT, :buffer)
|
6
7
|
HAML_HELPERS = s(:colon2, s(:const, :Haml), :Helpers)
|
8
|
+
HAML_HELPERS2 = s(:colon2, s(:colon3, :Haml), :Helpers)
|
7
9
|
JAVASCRIPT_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Javascript)
|
8
10
|
COFFEE_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Coffee)
|
9
11
|
|
@@ -14,130 +16,46 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
14
16
|
|
15
17
|
#Processes call, looking for template output
|
16
18
|
def process_call exp
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
exp = process_default exp
|
20
|
+
|
21
|
+
if buffer_append? exp
|
22
|
+
output = normalize_output(exp.first_arg)
|
23
|
+
res = get_pushed_value(output)
|
20
24
|
end
|
21
25
|
|
22
|
-
|
23
|
-
|
24
|
-
if (call? target and target.method == :_hamlout)
|
25
|
-
res = case method
|
26
|
-
when :adjust_tabs, :rstrip!, :attributes #Check attributes, maybe?
|
27
|
-
ignore
|
28
|
-
when :options, :buffer
|
29
|
-
exp
|
30
|
-
when :open_tag
|
31
|
-
process_call_args exp
|
32
|
-
else
|
33
|
-
arg = exp.first_arg
|
34
|
-
|
35
|
-
if arg
|
36
|
-
@inside_concat = true
|
37
|
-
exp.first_arg = process(arg)
|
38
|
-
out = normalize_output(exp.first_arg)
|
39
|
-
@inside_concat = false
|
40
|
-
else
|
41
|
-
raise "Empty _hamlout.#{method}()?"
|
42
|
-
end
|
43
|
-
|
44
|
-
if string? out
|
45
|
-
ignore
|
46
|
-
else
|
47
|
-
r = case method.to_s
|
48
|
-
when "push_text"
|
49
|
-
build_output_from_push_text(out)
|
50
|
-
when HAML_FORMAT_METHOD
|
51
|
-
if $4 == "true"
|
52
|
-
if string_interp? out
|
53
|
-
build_output_from_push_text(out, :escaped_output)
|
54
|
-
else
|
55
|
-
Sexp.new :format_escaped, out
|
56
|
-
end
|
57
|
-
else
|
58
|
-
if string_interp? out
|
59
|
-
build_output_from_push_text(out)
|
60
|
-
else
|
61
|
-
Sexp.new :format, out
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
else
|
66
|
-
raise "Unrecognized action on _hamlout: #{method}"
|
67
|
-
end
|
68
|
-
|
69
|
-
@javascript = false
|
70
|
-
r
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
res.line(exp.line)
|
75
|
-
res
|
76
|
-
|
77
|
-
#_hamlout.buffer <<
|
78
|
-
#This seems to be used rarely, but directly appends args to output buffer.
|
79
|
-
#Has something to do with values of blocks?
|
80
|
-
elsif sexp? target and method == :<< and is_buffer_target? target
|
81
|
-
@inside_concat = true
|
82
|
-
exp.first_arg = process(exp.first_arg)
|
83
|
-
out = normalize_output(exp.first_arg)
|
84
|
-
@inside_concat = false
|
85
|
-
|
86
|
-
if out.node_type == :str #ignore plain strings
|
87
|
-
ignore
|
88
|
-
else
|
89
|
-
add_output out
|
90
|
-
end
|
91
|
-
elsif target == nil and method == :render
|
92
|
-
#Process call to render()
|
93
|
-
exp.arglist = process exp.arglist
|
94
|
-
make_render_in_view exp
|
95
|
-
elsif target == nil and method == :find_and_preserve and exp.first_arg
|
96
|
-
process exp.first_arg
|
97
|
-
elsif method == :render_with_options
|
98
|
-
if target == JAVASCRIPT_FILTER or target == COFFEE_FILTER
|
99
|
-
@javascript = true
|
100
|
-
end
|
26
|
+
res or exp
|
27
|
+
end
|
101
28
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
exp.
|
106
|
-
exp
|
107
|
-
|
29
|
+
# _haml_out.buffer << ...
|
30
|
+
def buffer_append? exp
|
31
|
+
call? exp and
|
32
|
+
exp.target == HAML_BUFFER and
|
33
|
+
exp.method == :<<
|
34
|
+
end
|
35
|
+
|
36
|
+
PRESERVE_METHODS = [:find_and_preserve, :preserve]
|
37
|
+
|
38
|
+
def find_and_preserve? exp
|
39
|
+
call? exp and
|
40
|
+
PRESERVE_METHODS.include?(exp.method) and
|
41
|
+
exp.first_arg
|
108
42
|
end
|
109
43
|
|
110
44
|
#If inside an output stream, only return the final expression
|
111
45
|
def process_block exp
|
112
46
|
exp = exp.dup
|
113
47
|
exp.shift
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
else
|
122
|
-
exp.map! do |e|
|
123
|
-
res = process e
|
124
|
-
if res.empty?
|
125
|
-
nil
|
126
|
-
else
|
127
|
-
res
|
128
|
-
end
|
48
|
+
|
49
|
+
exp.map! do |e|
|
50
|
+
res = process e
|
51
|
+
if res.empty?
|
52
|
+
nil
|
53
|
+
else
|
54
|
+
res
|
129
55
|
end
|
130
|
-
Sexp.new(:rlist).concat(exp).compact
|
131
56
|
end
|
132
|
-
end
|
133
57
|
|
134
|
-
|
135
|
-
#TODO: Test this
|
136
|
-
def is_buffer_target? exp
|
137
|
-
exp.node_type == :call and
|
138
|
-
node_type? exp.target, :lvar and
|
139
|
-
exp.target.value == :_hamlout and
|
140
|
-
exp.method == :buffer
|
58
|
+
Sexp.new(:rlist).concat(exp).compact
|
141
59
|
end
|
142
60
|
|
143
61
|
#HAML likes to put interpolated values into _hamlout.push_text
|
@@ -158,7 +76,6 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
158
76
|
end
|
159
77
|
end
|
160
78
|
|
161
|
-
#Gets outputs from values interpolated into _hamlout.push_text
|
162
79
|
def get_pushed_value exp, default = :output
|
163
80
|
return exp unless sexp? exp
|
164
81
|
|
@@ -173,24 +90,71 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
173
90
|
exp
|
174
91
|
when :str, :ignore, :output, :escaped_output
|
175
92
|
exp
|
176
|
-
when :block, :rlist
|
177
|
-
exp.map! { |e| get_pushed_value
|
93
|
+
when :block, :rlist
|
94
|
+
exp.map! { |e| get_pushed_value(e, default) }
|
95
|
+
when :dstr
|
96
|
+
build_output_from_push_text(exp, default)
|
178
97
|
when :if
|
179
|
-
clauses = [get_pushed_value(exp.then_clause), get_pushed_value(exp.else_clause)].compact
|
98
|
+
clauses = [get_pushed_value(exp.then_clause, default), get_pushed_value(exp.else_clause, default)].compact
|
180
99
|
|
181
100
|
if clauses.length > 1
|
182
|
-
s(:or, *clauses)
|
101
|
+
s(:or, *clauses).line(exp.line)
|
183
102
|
else
|
184
103
|
clauses.first
|
185
104
|
end
|
186
|
-
|
187
|
-
if
|
188
|
-
|
189
|
-
elsif
|
190
|
-
|
105
|
+
when :call
|
106
|
+
if exp.method == :to_s or exp.method == :strip
|
107
|
+
get_pushed_value(exp.target, default)
|
108
|
+
elsif haml_helpers? exp.target and exp.method == :html_escape
|
109
|
+
get_pushed_value(exp.first_arg, :escaped_output)
|
110
|
+
elsif @javascript and (exp.method == :j or exp.method == :escape_javascript) # TODO: Remove - this is not safe
|
111
|
+
get_pushed_value(exp.first_arg, :escaped_output)
|
112
|
+
elsif find_and_preserve? exp or fix_textareas? exp
|
113
|
+
get_pushed_value(exp.first_arg, default)
|
114
|
+
elsif raw? exp
|
115
|
+
get_pushed_value(exp.first_arg, :output)
|
116
|
+
elsif hamlout_attributes? exp
|
117
|
+
ignore # ignore _hamlout.attributes calls
|
118
|
+
elsif exp.target.nil? and exp.method == :render
|
119
|
+
#Process call to render()
|
120
|
+
exp.arglist = process exp.arglist
|
121
|
+
make_render_in_view exp
|
122
|
+
elsif exp.method == :render_with_options
|
123
|
+
if exp.target == JAVASCRIPT_FILTER or exp.target == COFFEE_FILTER
|
124
|
+
@javascript = true
|
125
|
+
end
|
126
|
+
|
127
|
+
get_pushed_value(exp.first_arg, default)
|
128
|
+
@javascript = false
|
191
129
|
else
|
192
130
|
add_output exp, default
|
193
131
|
end
|
132
|
+
else
|
133
|
+
add_output exp, default
|
194
134
|
end
|
195
135
|
end
|
136
|
+
|
137
|
+
def haml_helpers? exp
|
138
|
+
# Sometimes its Haml::Helpers and
|
139
|
+
# sometimes its ::Haml::Helpers
|
140
|
+
exp == HAML_HELPERS or
|
141
|
+
exp == HAML_HELPERS2
|
142
|
+
end
|
143
|
+
|
144
|
+
def hamlout_attributes? exp
|
145
|
+
call? exp and
|
146
|
+
exp.target == HAMLOUT and
|
147
|
+
exp.method == :attributes
|
148
|
+
end
|
149
|
+
|
150
|
+
def fix_textareas? exp
|
151
|
+
call? exp and
|
152
|
+
exp.target == HAMLOUT and
|
153
|
+
exp.method == :fix_textareas!
|
154
|
+
end
|
155
|
+
|
156
|
+
def raw? exp
|
157
|
+
call? exp and
|
158
|
+
exp.method == :raw
|
159
|
+
end
|
196
160
|
end
|
@@ -19,16 +19,17 @@ module Brakeman
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
STRING_LENGTH_LIMIT = 50
|
23
|
+
|
22
24
|
# Join two string literals into one.
|
23
25
|
def join_strings lhs, rhs, original_exp = nil
|
24
26
|
if string? lhs and string? rhs
|
25
|
-
|
26
|
-
result.value = lhs.value + rhs.value
|
27
|
-
|
28
|
-
if result.value.length > 50
|
27
|
+
if (lhs.value.length + rhs.value.length > STRING_LENGTH_LIMIT)
|
29
28
|
# Avoid gigantic strings
|
30
29
|
lhs
|
31
30
|
else
|
31
|
+
result = Sexp.new(:str).line(lhs.line)
|
32
|
+
result.value = lhs.value + rhs.value
|
32
33
|
result
|
33
34
|
end
|
34
35
|
elsif call? lhs and lhs.method == :+ and string? lhs.first_arg and string? rhs
|
@@ -5,9 +5,9 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
|
|
5
5
|
|
6
6
|
def initialize tracker
|
7
7
|
super
|
8
|
-
|
9
|
-
@current_method = nil
|
8
|
+
|
10
9
|
@in_target = false
|
10
|
+
@processing_class = false
|
11
11
|
@calls = []
|
12
12
|
@cache = {}
|
13
13
|
end
|
@@ -23,10 +23,33 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
|
|
23
23
|
process exp
|
24
24
|
end
|
25
25
|
|
26
|
+
#For whatever reason, originally the indexing of calls
|
27
|
+
#was performed on individual method bodies (see process_defn).
|
28
|
+
#This method explicitly indexes all calls everywhere given any
|
29
|
+
#source.
|
30
|
+
def process_all_source exp, opts
|
31
|
+
@processing_class = true
|
32
|
+
process_source exp, opts
|
33
|
+
ensure
|
34
|
+
@processing_class = false
|
35
|
+
end
|
36
|
+
|
26
37
|
#Process body of method
|
27
38
|
def process_defn exp
|
28
|
-
return exp unless @current_method
|
29
|
-
|
39
|
+
return exp unless @current_method or @processing_class
|
40
|
+
|
41
|
+
# 'Normal' processing assumes the method name was given
|
42
|
+
# as an option to `process_source` but for `process_all_source`
|
43
|
+
# we don't want to do that.
|
44
|
+
if @current_method.nil?
|
45
|
+
@current_method = exp.method_name
|
46
|
+
process_all exp.body
|
47
|
+
@current_method = nil
|
48
|
+
else
|
49
|
+
process_all exp.body
|
50
|
+
end
|
51
|
+
|
52
|
+
exp
|
30
53
|
end
|
31
54
|
|
32
55
|
alias process_defs process_defn
|