brakeman-min 4.6.1 → 4.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +11 -0
- data/lib/brakeman/checks/base_check.rb +23 -1
- data/lib/brakeman/checks/check_cookie_serialization.rb +1 -1
- data/lib/brakeman/checks/check_cross_site_scripting.rb +1 -1
- data/lib/brakeman/checks/check_execute.rb +26 -1
- data/lib/brakeman/differ.rb +16 -28
- data/lib/brakeman/parsers/haml_embedded.rb +1 -1
- data/lib/brakeman/parsers/template_parser.rb +3 -1
- data/lib/brakeman/processors/alias_processor.rb +10 -0
- data/lib/brakeman/processors/base_processor.rb +2 -0
- data/lib/brakeman/processors/haml_template_processor.rb +86 -122
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +1 -1
- data/lib/brakeman/processors/template_alias_processor.rb +28 -0
- data/lib/brakeman/tracker/config.rb +33 -92
- data/lib/brakeman/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d12973a3773547b33ce1f73a567fd04fe1619683fcce1e1a3c62dd47c474c6d1
|
4
|
+
data.tar.gz: 8f10628132f2446664c4bcd350091f531cc5c6628240c6e65187871031ad231b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb6cfb7af8cc3cec4306bfab523ebbcc462c30f0c5547ab8df6937d8fa19c3e6002c66528918dfd17d58c32c4f81c5ce6c97b43aa22f7695b257ea36fe8019b2
|
7
|
+
data.tar.gz: 4e17c46419d7bb0b632542fa6a904a438e5413acf257240f895be5fb64f32af10206ce5d3ba2d21dd0cfed56c080842c75d423c8360743a9a1065e341a6c1759
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# 4.7.0
|
2
|
+
|
3
|
+
* Refactor `Brakeman::Differ#second_pass` (Benoit Côté-Jodoin)
|
4
|
+
* Ignore interpolation in `%W[]`
|
5
|
+
* Fix `version_between?` (Andrey Glushkov)
|
6
|
+
* Add support for `ruby_parser` 3.14.0
|
7
|
+
* Ignore `form_for` for XSS check
|
8
|
+
* Update Haml support to Haml 5.x
|
9
|
+
* Catch shell injection from `-c` shell commands (Jacob Evelyn)
|
10
|
+
* Correctly handle non-symbols in `CheckCookieSerialization` (Phil Turnbull)
|
11
|
+
|
1
12
|
# 4.6.1
|
2
13
|
|
3
14
|
* Fix Reverse Tabnabbing warning message (Steffen Schildknecht / Jörg Schiller)
|
@@ -39,6 +39,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
39
39
|
@active_record_models = nil
|
40
40
|
@mass_assign_disabled = nil
|
41
41
|
@has_user_input = nil
|
42
|
+
@in_array = false
|
42
43
|
@safe_input_attributes = Set[:to_i, :to_f, :arel_table, :id]
|
43
44
|
@comparison_ops = Set[:==, :!=, :>, :<, :>=, :<=]
|
44
45
|
end
|
@@ -109,9 +110,16 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
109
110
|
exp
|
110
111
|
end
|
111
112
|
|
113
|
+
def process_array exp
|
114
|
+
@in_array = true
|
115
|
+
process_default exp
|
116
|
+
ensure
|
117
|
+
@in_array = false
|
118
|
+
end
|
119
|
+
|
112
120
|
#Does not actually process string interpolation, but notes that it occurred.
|
113
121
|
def process_dstr exp
|
114
|
-
unless @string_interp # don't overwrite existing value
|
122
|
+
unless array_interp? exp or @string_interp # don't overwrite existing value
|
115
123
|
@string_interp = Match.new(:interp, exp)
|
116
124
|
end
|
117
125
|
|
@@ -120,6 +128,20 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
120
128
|
|
121
129
|
private
|
122
130
|
|
131
|
+
# Checking for
|
132
|
+
#
|
133
|
+
# %W[#{a}]
|
134
|
+
#
|
135
|
+
# which will be parsed as
|
136
|
+
#
|
137
|
+
# s(:array, s(:dstr, "", s(:evstr, s(:call, nil, :a))))
|
138
|
+
def array_interp? exp
|
139
|
+
@in_array and
|
140
|
+
string_interp? exp and
|
141
|
+
exp[1] == "".freeze and
|
142
|
+
exp.length == 3 # only one interpolated value
|
143
|
+
end
|
144
|
+
|
123
145
|
def always_safe_method? meth
|
124
146
|
@safe_input_attributes.include? meth or
|
125
147
|
@comparison_ops.include? meth
|
@@ -9,7 +9,7 @@ class Brakeman::CheckCookieSerialization < Brakeman::BaseCheck
|
|
9
9
|
tracker.find_call(target: :'Rails.application.config.action_dispatch', method: :cookies_serializer=).each do |result|
|
10
10
|
setting = result[:call].first_arg
|
11
11
|
|
12
|
-
if symbol? setting and
|
12
|
+
if symbol? setting and [:marshal, :hybrid].include? setting.value
|
13
13
|
warn :result => result,
|
14
14
|
:warning_type => "Remote Code Execution",
|
15
15
|
:warning_code => :unsafe_cookie_serialization,
|
@@ -287,7 +287,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
287
287
|
|
288
288
|
def setup
|
289
289
|
@ignore_methods = Set[:==, :!=, :button_to, :check_box, :content_tag, :escapeHTML, :escape_once,
|
290
|
-
:field_field, :fields_for, :h, :hidden_field,
|
290
|
+
:field_field, :fields_for, :form_for, :h, :hidden_field,
|
291
291
|
:hidden_field, :hidden_field_tag, :image_tag, :label,
|
292
292
|
:link_to, :mail_to, :radio_button, :select,
|
293
293
|
:submit_tag, :text_area, :text_field,
|
@@ -21,6 +21,10 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
21
21
|
SHELL_ESCAPE_MODULE_METHODS = Set[:escape, :join, :shellescape, :shelljoin]
|
22
22
|
SHELL_ESCAPE_MIXIN_METHODS = Set[:shellescape, :shelljoin]
|
23
23
|
|
24
|
+
# These are common shells that are known to allow the execution of commands
|
25
|
+
# via a -c flag. See dash_c_shell_command? for more info.
|
26
|
+
KNOWN_SHELL_COMMANDS = Set["sh", "bash", "ksh", "csh", "tcsh", "zsh"]
|
27
|
+
|
24
28
|
SHELLWORDS = s(:const, :Shellwords)
|
25
29
|
|
26
30
|
#Check models, controllers, and views for command injection.
|
@@ -42,6 +46,8 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
49
|
+
private
|
50
|
+
|
45
51
|
#Processes results from Tracker#find_call.
|
46
52
|
def process_result result
|
47
53
|
call = result[:call]
|
@@ -54,7 +60,17 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
54
60
|
failure = include_user_input?(args) || dangerous_interp?(args)
|
55
61
|
end
|
56
62
|
when :system, :exec
|
57
|
-
|
63
|
+
# Normally, if we're in a `system` or `exec` call, we only are worried
|
64
|
+
# about shell injection when there's a single argument, because comma-
|
65
|
+
# separated arguments are always escaped by Ruby. However, an exception is
|
66
|
+
# when the first two arguments are something like "bash -c" because then
|
67
|
+
# the third argument is effectively the command being run and might be
|
68
|
+
# a malicious executable if it comes (partially or fully) from user input.
|
69
|
+
if dash_c_shell_command?(first_arg, call.second_arg)
|
70
|
+
failure = include_user_input?(args[3]) || dangerous_interp?(args[3])
|
71
|
+
else
|
72
|
+
failure = include_user_input?(first_arg) || dangerous_interp?(first_arg)
|
73
|
+
end
|
58
74
|
else
|
59
75
|
failure = include_user_input?(args) || dangerous_interp?(args)
|
60
76
|
end
|
@@ -77,6 +93,15 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
77
93
|
end
|
78
94
|
end
|
79
95
|
|
96
|
+
# @return [Boolean] true iff the command given by `first_arg`, `second_arg`
|
97
|
+
# invokes a new shell process via `<shell_command> -c` (like `bash -c`)
|
98
|
+
def dash_c_shell_command?(first_arg, second_arg)
|
99
|
+
string?(first_arg) &&
|
100
|
+
KNOWN_SHELL_COMMANDS.include?(first_arg.value) &&
|
101
|
+
string?(second_arg) &&
|
102
|
+
second_arg.value == "-c"
|
103
|
+
end
|
104
|
+
|
80
105
|
def check_open_calls
|
81
106
|
tracker.find_call(:targets => [nil, :Kernel], :method => :open).each do |result|
|
82
107
|
if match = dangerous_open_arg?(result[:call].first_arg)
|
data/lib/brakeman/differ.rb
CHANGED
@@ -24,43 +24,31 @@ class Brakeman::Differ
|
|
24
24
|
# second pass to cleanup any vulns which have changed in line number only.
|
25
25
|
# Given a list of new warnings, delete pairs of new/fixed vulns that differ
|
26
26
|
# only by line number.
|
27
|
-
# Horrible O(n^2) performance. Keep n small :-/
|
28
27
|
def second_pass(warnings)
|
29
|
-
|
30
|
-
|
31
|
-
elements_deleted_offset = 0
|
28
|
+
new_fingerprints = Set.new(warnings[:new].map(&method(:fingerprint)))
|
29
|
+
fixed_fingerprints = Set.new(warnings[:fixed].map(&method(:fingerprint)))
|
32
30
|
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
31
|
+
# Remove warnings which fingerprints are both in :new and :fixed
|
32
|
+
shared_fingerprints = new_fingerprints.intersection(fixed_fingerprints)
|
33
|
+
|
34
|
+
unless shared_fingerprints.empty?
|
35
|
+
warnings[:new].delete_if do |warning|
|
36
|
+
shared_fingerprints.include?(fingerprint(warning))
|
37
|
+
end
|
38
|
+
|
39
|
+
warnings[:fixed].delete_if do |warning|
|
40
|
+
shared_fingerprints.include?(fingerprint(warning))
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
46
44
|
warnings
|
47
45
|
end
|
48
46
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
new_warning = new_warning.to_hash
|
53
|
-
fixed_warning = fixed_warning.to_hash
|
54
|
-
end
|
55
|
-
|
56
|
-
if new_warning[:fingerprint] and fixed_warning[:fingerprint]
|
57
|
-
new_warning[:fingerprint] == fixed_warning[:fingerprint]
|
47
|
+
def fingerprint(warning)
|
48
|
+
if warning.is_a?(Brakeman::Warning)
|
49
|
+
warning.fingerprint
|
58
50
|
else
|
59
|
-
|
60
|
-
return false if new_warning[attr] != fixed_warning[attr]
|
61
|
-
end
|
62
|
-
|
63
|
-
true
|
51
|
+
warning[:fingerprint]
|
64
52
|
end
|
65
53
|
end
|
66
54
|
end
|
@@ -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
|
@@ -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
|
@@ -1198,6 +1201,13 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
1198
1201
|
call? exp and exp.method == :raise
|
1199
1202
|
end
|
1200
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
|
+
|
1201
1211
|
#Set variable to given value.
|
1202
1212
|
#Creates "branched" versions of values when appropriate.
|
1203
1213
|
#Avoids creating multiple branched versions inside same
|
@@ -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
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
|
@@ -75,7 +75,7 @@ class Brakeman::Rails2ConfigProcessor < Brakeman::BasicProcessor
|
|
75
75
|
def process_cdecl exp
|
76
76
|
#Set Rails version required
|
77
77
|
if exp.lhs == :RAILS_GEM_VERSION
|
78
|
-
@tracker.config.
|
78
|
+
@tracker.config.set_rails_version exp.rhs.value
|
79
79
|
end
|
80
80
|
|
81
81
|
exp
|
@@ -32,6 +32,34 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
def process_lasgn exp
|
36
|
+
if exp.lhs == :haml_temp or haml_capture? exp.rhs
|
37
|
+
exp.rhs = process exp.rhs
|
38
|
+
|
39
|
+
# Avoid propagating contents of block
|
40
|
+
if node_type? exp.rhs, :iter
|
41
|
+
new_exp = exp.dup
|
42
|
+
new_exp.rhs = exp.rhs.block_call
|
43
|
+
|
44
|
+
super new_exp
|
45
|
+
|
46
|
+
exp # Still save the original, though
|
47
|
+
else
|
48
|
+
super exp
|
49
|
+
end
|
50
|
+
else
|
51
|
+
super exp
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
HAML_CAPTURE = [:capture, :capture_haml]
|
56
|
+
|
57
|
+
def haml_capture? exp
|
58
|
+
node_type? exp, :iter and
|
59
|
+
call? exp.block_call and
|
60
|
+
HAML_CAPTURE.include? exp.block_call.method
|
61
|
+
end
|
62
|
+
|
35
63
|
#Determine template name
|
36
64
|
def template_name name
|
37
65
|
if !name.to_s.include?('/') && @template.name.to_s.include?('/')
|
@@ -4,10 +4,8 @@ module Brakeman
|
|
4
4
|
class Config
|
5
5
|
include Util
|
6
6
|
|
7
|
-
attr_reader :rails, :tracker
|
8
|
-
attr_accessor :rails_version, :ruby_version
|
7
|
+
attr_reader :gems, :rails, :ruby_version, :tracker
|
9
8
|
attr_writer :erubis, :escape_html
|
10
|
-
attr_reader :gems
|
11
9
|
|
12
10
|
def initialize tracker
|
13
11
|
@tracker = tracker
|
@@ -20,7 +18,7 @@ module Brakeman
|
|
20
18
|
end
|
21
19
|
|
22
20
|
def default_protect_from_forgery?
|
23
|
-
if version_between? "5.2.0", "9.9.9"
|
21
|
+
if version_between? "5.2.0.beta1", "9.9.9"
|
24
22
|
if @rails.dig(:action_controller, :default_protect_from_forgery) == Sexp.new(:false)
|
25
23
|
return false
|
26
24
|
else
|
@@ -44,12 +42,18 @@ module Brakeman
|
|
44
42
|
true? @rails.dig(:active_support, :escape_html_entities_in_json)
|
45
43
|
end
|
46
44
|
|
45
|
+
def escape_filter_interpolations?
|
46
|
+
# TODO see if app is actually turning this off itself
|
47
|
+
has_gem?(:haml) and
|
48
|
+
version_between? "5.0.0", "5.99", gem_version(:haml)
|
49
|
+
end
|
50
|
+
|
47
51
|
def whitelist_attributes?
|
48
52
|
@rails.dig(:active_record, :whitelist_attributes) == Sexp.new(:true)
|
49
53
|
end
|
50
54
|
|
51
55
|
def gem_version name
|
52
|
-
@gems.dig(name, :version)
|
56
|
+
extract_version @gems.dig(name, :version)
|
53
57
|
end
|
54
58
|
|
55
59
|
def add_gem name, version, file, line
|
@@ -69,11 +73,16 @@ module Brakeman
|
|
69
73
|
@gems[name]
|
70
74
|
end
|
71
75
|
|
72
|
-
def set_rails_version
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
76
|
+
def set_rails_version version = nil
|
77
|
+
version = if version
|
78
|
+
# Only used by Rails2ConfigProcessor right now
|
79
|
+
extract_version(version)
|
80
|
+
else
|
81
|
+
gem_version(:rails) || gem_version(:railties)
|
82
|
+
end
|
83
|
+
|
84
|
+
if version
|
85
|
+
@rails_version = version
|
77
86
|
|
78
87
|
if tracker.options[:rails3].nil? and tracker.options[:rails4].nil?
|
79
88
|
if @rails_version.start_with? "3"
|
@@ -102,16 +111,22 @@ module Brakeman
|
|
102
111
|
@escape_html = true
|
103
112
|
Brakeman.notify "[Notice] Escaping HTML by default"
|
104
113
|
end
|
114
|
+
end
|
105
115
|
|
106
|
-
|
116
|
+
def rails_version
|
117
|
+
# This needs to be here because Util#rails_version calls Tracker::Config#rails_version
|
118
|
+
# but Tracker::Config includes Util...
|
119
|
+
@rails_version
|
107
120
|
end
|
108
121
|
|
109
122
|
def set_ruby_version version
|
123
|
+
@ruby_version = extract_version(version)
|
124
|
+
end
|
125
|
+
|
126
|
+
def extract_version version
|
110
127
|
return unless version.is_a? String
|
111
128
|
|
112
|
-
|
113
|
-
self.ruby_version = $1
|
114
|
-
end
|
129
|
+
version[/\d+\.\d+(\.\d+.*)?/]
|
115
130
|
end
|
116
131
|
|
117
132
|
#Returns true if low_version <= RAILS_VERSION <= high_version
|
@@ -121,89 +136,15 @@ module Brakeman
|
|
121
136
|
current_version ||= rails_version
|
122
137
|
return false unless current_version
|
123
138
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
version.each_with_index do |v, i|
|
129
|
-
if lower? v, low_version.fetch(i, 0)
|
130
|
-
return false
|
131
|
-
elsif higher? v, low_version.fetch(i, 0)
|
132
|
-
break
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
version.each_with_index do |v, i|
|
137
|
-
if higher? v, high_version.fetch(i, 0)
|
138
|
-
return false
|
139
|
-
elsif lower? v, high_version.fetch(i, 0)
|
140
|
-
break
|
141
|
-
end
|
142
|
-
end
|
139
|
+
low = Gem::Version.new(low_version)
|
140
|
+
high = Gem::Version.new(high_version)
|
141
|
+
current = Gem::Version.new(current_version)
|
143
142
|
|
144
|
-
|
143
|
+
current.between?(low, high)
|
145
144
|
end
|
146
145
|
|
147
146
|
def session_settings
|
148
147
|
@rails.dig(:action_controller, :session)
|
149
148
|
end
|
150
|
-
|
151
|
-
private
|
152
|
-
|
153
|
-
# Brakeman does not support Haml 5 yet.
|
154
|
-
# (https://github.com/presidentbeef/brakeman/issues/1370) Fortunately, Haml
|
155
|
-
# 5 doesn't add much new syntax, and brakeman (which uses the haml 4 parser)
|
156
|
-
# will parse most Haml 5 files without errors. Therefore, we only print a
|
157
|
-
# warning here, instead of raising an error.
|
158
|
-
def check_haml_version
|
159
|
-
return if supported_haml_version?
|
160
|
-
Brakeman.notify <<~EOS
|
161
|
-
Brakeman does not fully support Haml 5 yet. Your Gemfile (or gemspec)
|
162
|
-
allows Haml 5. Brakeman uses the Haml 4 parser and thus may produce
|
163
|
-
errors when parsing Haml 5 syntax. If Brakeman encounters such an error,
|
164
|
-
it will be unable to scan that file.
|
165
|
-
EOS
|
166
|
-
end
|
167
|
-
|
168
|
-
def convert_version_number value
|
169
|
-
if value.match(/\A\d+\z/)
|
170
|
-
value.to_i
|
171
|
-
else
|
172
|
-
value
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def lower? lhs, rhs
|
177
|
-
if lhs.class == rhs.class
|
178
|
-
lhs < rhs
|
179
|
-
else
|
180
|
-
false
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
# Brakeman does not support Haml 5 yet. See `check_haml_version`.
|
185
|
-
#
|
186
|
-
# This method is messy because all we have is a version `Requirement` (like
|
187
|
-
# `~> 5.0.3`, or `> 4.99`) The only way I could think of was to loop over
|
188
|
-
# known Haml 5 versions and test whether the `Requirement` is satisfied. I
|
189
|
-
# included '5.99.99' in the list so that this method might stand a chance of
|
190
|
-
# working in the future.
|
191
|
-
def supported_haml_version?
|
192
|
-
haml_version = gem_version(:haml)
|
193
|
-
return true unless haml_version
|
194
|
-
|
195
|
-
requirement = Gem::Requirement.new(haml_version)
|
196
|
-
['5.99.99', '5.1.1', '5.1.0', '5.0.4', '5.0.3', '5.0.2', '5.0.1', '5.0.0'].none? do |v|
|
197
|
-
requirement.satisfied_by?(Gem::Version.new(v))
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def higher? lhs, rhs
|
202
|
-
if lhs.class == rhs.class
|
203
|
-
lhs > rhs
|
204
|
-
else
|
205
|
-
false
|
206
|
-
end
|
207
|
-
end
|
208
149
|
end
|
209
150
|
end
|
data/lib/brakeman/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brakeman-min
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Collins
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain:
|
11
11
|
- brakeman-public_cert.pem
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|