brakeman-lib 5.4.0 → 6.0.0
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 +22 -0
- data/README.md +3 -3
- data/lib/brakeman/app_tree.rb +0 -1
- data/lib/brakeman/checks/base_check.rb +2 -3
- data/lib/brakeman/checks/check_content_tag.rb +8 -5
- data/lib/brakeman/checks/check_eol_ruby.rb +3 -1
- data/lib/brakeman/checks/check_redirect.rb +60 -29
- data/lib/brakeman/checks/check_unscoped_find.rb +8 -0
- data/lib/brakeman/checks/eol_check.rb +2 -2
- data/lib/brakeman/processors/alias_processor.rb +50 -19
- data/lib/brakeman/processors/gem_processor.rb +2 -2
- data/lib/brakeman/report/report_github.rb +1 -1
- data/lib/brakeman/rescanner.rb +3 -1
- data/lib/brakeman/scanner.rb +1 -2
- data/lib/brakeman/tracker/config.rb +43 -4
- data/lib/brakeman/tracker.rb +1 -1
- data/lib/brakeman/util.rb +20 -4
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman.rb +6 -2
- metadata +6 -20
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: baf72edb48740cecdeb55594386bfa2fd6284a498d1ab7991d24bf30715f424f
|
|
4
|
+
data.tar.gz: 2510eda8d6bc947676d872f3980492c21d227679ae2761a5847ce782f538f628
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5a7739712e782e33cbfe5de51fa2e8c2f53e2366983e113c64c0acdc820a5b04034fc9917da0ce999503fdc897e30218860d4534bbc41b164892629bdfbdac31
|
|
7
|
+
data.tar.gz: d9b526f6c7289543c1c0429722e4b99c276fe4ce145ce7ab4bcfadfec9455dba0fe9e3c0aeceab00d8ba790e0f4076a9459c574a138476eb9b344e3cb3ea6e9a
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
# 6.0.0 - 2023-05-24
|
|
2
|
+
|
|
3
|
+
* Add obsolete fingerprints to comparison report
|
|
4
|
+
* Warn about missing CSRF protection when defaults are not loaded (Chris Kruger)
|
|
5
|
+
* Scan directories that include the word `public`
|
|
6
|
+
* Raise minimum Ruby version to 3.0
|
|
7
|
+
* Drop support for Ruby 1.8/1.9 syntax
|
|
8
|
+
* Fix end-of-life dates for Ruby
|
|
9
|
+
* Fix false positive with `content_tag` in newer Rails
|
|
10
|
+
|
|
11
|
+
# 5.4.1 - 2023-02-21
|
|
12
|
+
|
|
13
|
+
* Fix file/line location for EOL software warnings
|
|
14
|
+
* Revise checking for request.env to only consider request headers
|
|
15
|
+
* Add `redirect_back` and `redirect_back_or_to` to open redirect check
|
|
16
|
+
* Support Rails 7 redirect options
|
|
17
|
+
* Add Rails 6.1 and 7.0 default configuration values
|
|
18
|
+
* Prevent redirects using `url_from` being marked as unsafe (Lachlan Sylvester)
|
|
19
|
+
* Warn about unscoped find for `find_by(id: ...)`
|
|
20
|
+
* Support `presence`, `presence_in` and `in?`
|
|
21
|
+
* Fix issue with `if` expressions in `when` clauses
|
|
22
|
+
|
|
1
23
|
# 5.4.0 - 2022-11-17
|
|
2
24
|
|
|
3
25
|
* Use relative paths for CodeClimate report format (Mike Poage)
|
data/README.md
CHANGED
|
@@ -64,9 +64,9 @@ Outside of Rails root (note that the output file is relative to path/to/rails/ap
|
|
|
64
64
|
|
|
65
65
|
# Compatibility
|
|
66
66
|
|
|
67
|
-
Brakeman should work with any version of Rails from 2.3.x to
|
|
67
|
+
Brakeman should work with any version of Rails from 2.3.x to 7.x.
|
|
68
68
|
|
|
69
|
-
Brakeman can analyze code written with Ruby
|
|
69
|
+
Brakeman can analyze code written with Ruby 2.0 syntax and newer, but requires at least Ruby 3.0.0 to run.
|
|
70
70
|
|
|
71
71
|
# Basic Options
|
|
72
72
|
|
|
@@ -182,7 +182,7 @@ There is a [plugin available](http://brakemanscanner.org/docs/jenkins/) for Jenk
|
|
|
182
182
|
|
|
183
183
|
For even more continuous testing, try the [Guard plugin](https://github.com/guard/guard-brakeman).
|
|
184
184
|
|
|
185
|
-
There are a couple [
|
|
185
|
+
There are a couple [GitHub Actions](https://github.com/marketplace?type=actions&query=brakeman) available.
|
|
186
186
|
|
|
187
187
|
# Building
|
|
188
188
|
|
data/lib/brakeman/app_tree.rb
CHANGED
|
@@ -76,7 +76,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
76
76
|
@has_user_input = Match.new(:params, exp)
|
|
77
77
|
elsif cookies? target
|
|
78
78
|
@has_user_input = Match.new(:cookies, exp)
|
|
79
|
-
elsif
|
|
79
|
+
elsif request_headers? target
|
|
80
80
|
@has_user_input = Match.new(:request, exp)
|
|
81
81
|
elsif sexp? target and model_name? target[1] #TODO: Can this be target.target?
|
|
82
82
|
@has_user_input = Match.new(:model, exp)
|
|
@@ -313,7 +313,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
313
313
|
return Match.new(:params, exp)
|
|
314
314
|
elsif cookies? exp
|
|
315
315
|
return Match.new(:cookies, exp)
|
|
316
|
-
elsif
|
|
316
|
+
elsif request_headers? exp
|
|
317
317
|
return Match.new(:request, exp)
|
|
318
318
|
else
|
|
319
319
|
has_immediate_user_input? exp.target
|
|
@@ -467,7 +467,6 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
467
467
|
version_between? version, "2.3.18.99", tracker.config.gem_version(:'railslts-version')
|
|
468
468
|
end
|
|
469
469
|
|
|
470
|
-
|
|
471
470
|
def version_between? low_version, high_version, current_version = nil
|
|
472
471
|
tracker.config.version_between? low_version, high_version, current_version
|
|
473
472
|
end
|
|
@@ -73,11 +73,14 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
|
|
|
73
73
|
check_argument result, content
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
#
|
|
77
|
-
if
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
# This changed in Rails 6.1.6
|
|
77
|
+
if version_between? '0.0.0', '6.1.5'
|
|
78
|
+
#Attribute keys are never escaped, so check them for user input
|
|
79
|
+
if not @matched and hash? attributes and not request_value? attributes
|
|
80
|
+
hash_iterate(attributes) do |k, _v|
|
|
81
|
+
check_argument result, k
|
|
82
|
+
return if @matched
|
|
83
|
+
end
|
|
81
84
|
end
|
|
82
85
|
end
|
|
83
86
|
|
|
@@ -21,6 +21,8 @@ class Brakeman::CheckEOLRuby < Brakeman::EOLCheck
|
|
|
21
21
|
['2.5.0', '2.5.99'] => Date.new(2021, 3, 31),
|
|
22
22
|
['2.6.0', '2.6.99'] => Date.new(2022, 3, 31),
|
|
23
23
|
['2.7.0', '2.7.99'] => Date.new(2023, 3, 31),
|
|
24
|
-
['3.0.0', '
|
|
24
|
+
['3.0.0', '3.0.99'] => Date.new(2024, 3, 31),
|
|
25
|
+
['3.1.0', '3.1.99'] => Date.new(2025, 3, 31),
|
|
26
|
+
['3.2.0', '3.2.99'] => Date.new(2026, 3, 31),
|
|
25
27
|
}
|
|
26
28
|
end
|
|
@@ -11,8 +11,6 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
|
|
|
11
11
|
@description = "Looks for calls to redirect_to with user input as arguments"
|
|
12
12
|
|
|
13
13
|
def run_check
|
|
14
|
-
Brakeman.debug "Finding calls to redirect_to()"
|
|
15
|
-
|
|
16
14
|
@model_find_calls = Set[:all, :create, :create!, :find, :find_by_sql, :first, :first!, :last, :last!, :new, :sole]
|
|
17
15
|
|
|
18
16
|
if tracker.options[:rails3]
|
|
@@ -27,7 +25,9 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
|
|
|
27
25
|
@model_find_calls << :find_sole_by
|
|
28
26
|
end
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
methods = [:redirect_to, :redirect_back, :redirect_back_or_to]
|
|
29
|
+
|
|
30
|
+
@tracker.find_call(:target => false, :methods => methods).each do |res|
|
|
31
31
|
process_result res
|
|
32
32
|
end
|
|
33
33
|
end
|
|
@@ -36,18 +36,28 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
|
|
|
36
36
|
return unless original? result
|
|
37
37
|
|
|
38
38
|
call = result[:call]
|
|
39
|
-
method = call.method
|
|
40
|
-
|
|
41
39
|
opt = call.first_arg
|
|
42
40
|
|
|
43
|
-
|
|
41
|
+
# Location is specified with `fallback_location:`
|
|
42
|
+
# otherwise the arguments do not contain a location and
|
|
43
|
+
# the call can be ignored
|
|
44
|
+
if call.method == :redirect_back
|
|
45
|
+
if hash? opt and location = hash_access(opt, :fallback_location)
|
|
46
|
+
opt = location
|
|
47
|
+
else
|
|
48
|
+
return
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if not protected_by_raise?(call) and
|
|
44
53
|
not only_path?(call) and
|
|
45
54
|
not explicit_host?(opt) and
|
|
46
55
|
not slice_call?(opt) and
|
|
47
56
|
not safe_permit?(opt) and
|
|
48
|
-
|
|
57
|
+
not disallow_other_host?(call) and
|
|
58
|
+
res = include_user_input?(opt)
|
|
49
59
|
|
|
50
|
-
if res.type == :immediate
|
|
60
|
+
if res.type == :immediate and not allow_other_host?(call)
|
|
51
61
|
confidence = :high
|
|
52
62
|
else
|
|
53
63
|
confidence = :weak
|
|
@@ -68,42 +78,42 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
|
|
|
68
78
|
#is being output directly. This is necessary because of tracker.options[:check_arguments]
|
|
69
79
|
#which can be used to enable/disable reporting output of method calls which use
|
|
70
80
|
#user input as arguments.
|
|
71
|
-
def include_user_input?
|
|
81
|
+
def include_user_input? opt, immediate = :immediate
|
|
72
82
|
Brakeman.debug "Checking if call includes user input"
|
|
73
83
|
|
|
74
|
-
arg = call.first_arg
|
|
75
|
-
|
|
76
84
|
# if the first argument is an array, rails assumes you are building a
|
|
77
85
|
# polymorphic route, which will never jump off-host
|
|
78
|
-
return false if array?
|
|
86
|
+
return false if array? opt
|
|
79
87
|
|
|
80
88
|
if tracker.options[:ignore_redirect_to_model]
|
|
81
|
-
if model_instance?(
|
|
89
|
+
if model_instance?(opt) or decorated_model?(opt)
|
|
82
90
|
return false
|
|
83
91
|
end
|
|
84
92
|
end
|
|
85
93
|
|
|
86
|
-
if res = has_immediate_model?(
|
|
87
|
-
unless call?
|
|
94
|
+
if res = has_immediate_model?(opt)
|
|
95
|
+
unless call? opt and opt.method.to_s =~ /_path/
|
|
88
96
|
return Match.new(immediate, res)
|
|
89
97
|
end
|
|
90
|
-
elsif call?
|
|
91
|
-
if request_value?
|
|
92
|
-
return Match.new(immediate,
|
|
93
|
-
elsif
|
|
94
|
-
return Match.new(immediate,
|
|
95
|
-
elsif arg.method == :url_for and include_user_input? arg
|
|
96
|
-
return Match.new(immediate, arg)
|
|
98
|
+
elsif call? opt
|
|
99
|
+
if request_value? opt
|
|
100
|
+
return Match.new(immediate, opt)
|
|
101
|
+
elsif opt.method == :url_for and include_user_input? opt.first_arg
|
|
102
|
+
return Match.new(immediate, opt)
|
|
97
103
|
#Ignore helpers like some_model_url?
|
|
98
|
-
elsif
|
|
104
|
+
elsif opt.method.to_s =~ /_(url|path)\z/
|
|
105
|
+
return false
|
|
106
|
+
elsif opt.method == :url_from
|
|
99
107
|
return false
|
|
100
108
|
end
|
|
101
|
-
elsif request_value?
|
|
102
|
-
return Match.new(immediate,
|
|
109
|
+
elsif request_value? opt
|
|
110
|
+
return Match.new(immediate, opt)
|
|
111
|
+
elsif node_type? opt, :or
|
|
112
|
+
return (include_user_input?(opt.lhs) or include_user_input?(opt.rhs))
|
|
103
113
|
end
|
|
104
114
|
|
|
105
|
-
if tracker.options[:check_arguments] and call?
|
|
106
|
-
include_user_input?
|
|
115
|
+
if tracker.options[:check_arguments] and call? opt
|
|
116
|
+
include_user_input? opt.first_arg, false #I'm doubting if this is really necessary...
|
|
107
117
|
else
|
|
108
118
|
false
|
|
109
119
|
end
|
|
@@ -208,7 +218,7 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
|
|
|
208
218
|
def friendly_model? exp
|
|
209
219
|
call? exp and model_name? exp.target and exp.method == :friendly
|
|
210
220
|
end
|
|
211
|
-
|
|
221
|
+
|
|
212
222
|
#Returns true if exp is (probably) a decorated model instance
|
|
213
223
|
#using the Draper gem
|
|
214
224
|
def decorated_model? exp
|
|
@@ -249,7 +259,7 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
|
|
|
249
259
|
if call? exp and params? exp.target and exp.method == :permit
|
|
250
260
|
exp.each_arg do |opt|
|
|
251
261
|
if symbol? opt and DANGEROUS_KEYS.include? opt.value
|
|
252
|
-
return false
|
|
262
|
+
return false
|
|
253
263
|
end
|
|
254
264
|
end
|
|
255
265
|
|
|
@@ -258,4 +268,25 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
|
|
|
258
268
|
|
|
259
269
|
false
|
|
260
270
|
end
|
|
271
|
+
|
|
272
|
+
def protected_by_raise? call
|
|
273
|
+
raise_on_redirects? and
|
|
274
|
+
not allow_other_host? call
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def raise_on_redirects?
|
|
278
|
+
@raise_on_redirects ||= true?(tracker.config.rails.dig(:action_controller, :raise_on_open_redirects))
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def allow_other_host? call
|
|
282
|
+
opt = call.last_arg
|
|
283
|
+
|
|
284
|
+
hash? opt and true? hash_access(opt, :allow_other_host)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def disallow_other_host? call
|
|
288
|
+
opt = call.last_arg
|
|
289
|
+
|
|
290
|
+
hash? opt and false? hash_access(opt, :allow_other_host)
|
|
291
|
+
end
|
|
261
292
|
end
|
|
@@ -23,6 +23,14 @@ class Brakeman::CheckUnscopedFind < Brakeman::BaseCheck
|
|
|
23
23
|
calls.each do |call|
|
|
24
24
|
process_result call
|
|
25
25
|
end
|
|
26
|
+
|
|
27
|
+
tracker.find_call(:method => :find_by, :targets => associated_model_names).each do |result|
|
|
28
|
+
arg = result[:call].first_arg
|
|
29
|
+
|
|
30
|
+
if hash? arg and hash_access(arg, :id)
|
|
31
|
+
process_result result
|
|
32
|
+
end
|
|
33
|
+
end
|
|
26
34
|
end
|
|
27
35
|
|
|
28
36
|
def process_result result
|
|
@@ -34,7 +34,7 @@ class Brakeman::EOLCheck < Brakeman::BaseCheck
|
|
|
34
34
|
warning_code: :"pending_eol_#{library}",
|
|
35
35
|
message: msg("Support for ", msg_version(version, library.capitalize), " ends on #{eol_date}"),
|
|
36
36
|
confidence: confidence,
|
|
37
|
-
gem_info: gemfile_or_environment,
|
|
37
|
+
gem_info: gemfile_or_environment(library),
|
|
38
38
|
:cwe_id => [1104]
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -43,7 +43,7 @@ class Brakeman::EOLCheck < Brakeman::BaseCheck
|
|
|
43
43
|
warning_code: :"eol_#{library}",
|
|
44
44
|
message: msg("Support for ", msg_version(version, library.capitalize), " ended on #{eol_date}"),
|
|
45
45
|
confidence: :high,
|
|
46
|
-
gem_info: gemfile_or_environment,
|
|
46
|
+
gem_info: gemfile_or_environment(library),
|
|
47
47
|
:cwe_id => [1104]
|
|
48
48
|
end
|
|
49
49
|
end
|
|
@@ -300,11 +300,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
300
300
|
if array? target and first_arg.nil? and sexp? target[1]
|
|
301
301
|
exp = target[1]
|
|
302
302
|
end
|
|
303
|
-
when :freeze
|
|
304
|
-
unless target.nil?
|
|
305
|
-
exp = target
|
|
306
|
-
end
|
|
307
|
-
when :dup
|
|
303
|
+
when :freeze, :dup, :presence
|
|
308
304
|
unless target.nil?
|
|
309
305
|
exp = target
|
|
310
306
|
end
|
|
@@ -332,6 +328,17 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
332
328
|
exp = res
|
|
333
329
|
end
|
|
334
330
|
end
|
|
331
|
+
when :presence_in
|
|
332
|
+
arg = exp.first_arg
|
|
333
|
+
|
|
334
|
+
if node_type? arg, :array
|
|
335
|
+
# 1.presence_in [1,2,3]
|
|
336
|
+
if arg.include? target
|
|
337
|
+
exp = target
|
|
338
|
+
elsif all_literals? arg
|
|
339
|
+
exp = safe_literal(exp.line)
|
|
340
|
+
end
|
|
341
|
+
end
|
|
335
342
|
end
|
|
336
343
|
|
|
337
344
|
exp
|
|
@@ -862,6 +869,17 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
862
869
|
(all_literals? exp.target or dir_glob? exp.target)
|
|
863
870
|
end
|
|
864
871
|
|
|
872
|
+
# Check if exp is a call to Array#include? on an array literal
|
|
873
|
+
# that contains all literal values. For example:
|
|
874
|
+
#
|
|
875
|
+
# x.in? [1, 2, "a"]
|
|
876
|
+
#
|
|
877
|
+
def in_array_all_literals? exp
|
|
878
|
+
call? exp and
|
|
879
|
+
exp.method == :in? and
|
|
880
|
+
all_literals? exp.first_arg
|
|
881
|
+
end
|
|
882
|
+
|
|
865
883
|
# Check if exp is a call to Hash#include? on a hash literal
|
|
866
884
|
# that contains all literal values. For example:
|
|
867
885
|
#
|
|
@@ -915,28 +933,30 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
915
933
|
scope do
|
|
916
934
|
@branch_env = env.current
|
|
917
935
|
branch_index = 2 + i # s(:if, condition, then_branch, else_branch)
|
|
918
|
-
|
|
936
|
+
exp[branch_index] = if i == 0 and hash_or_array_include_all_literals? condition
|
|
919
937
|
# If the condition is ["a", "b"].include? x
|
|
920
|
-
# set x to
|
|
938
|
+
# set x to safe_literal inside the true branch
|
|
921
939
|
var = condition.first_arg
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
940
|
+
value = safe_literal(var.line)
|
|
941
|
+
process_branch_with_value(var, value, branch, i)
|
|
942
|
+
elsif i == 0 and in_array_all_literals? condition
|
|
943
|
+
# If the condition is x.in? ["a", "b"]
|
|
944
|
+
# set x to safe_literal inside the true branch
|
|
945
|
+
var = condition.target
|
|
946
|
+
value = safe_literal(var.line)
|
|
947
|
+
process_branch_with_value(var, value, branch, i)
|
|
926
948
|
elsif i == 0 and equality_check? condition
|
|
927
949
|
# For conditions like a == b,
|
|
928
950
|
# set a to b inside the true branch
|
|
929
951
|
var = condition.target
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
exp[branch_index] = process_if_branch branch
|
|
933
|
-
env.current[var] = previous_value
|
|
952
|
+
value = condition.first_arg
|
|
953
|
+
process_branch_with_value(var, value, branch, i)
|
|
934
954
|
elsif i == 1 and hash_or_array_include_all_literals? condition and early_return? branch
|
|
935
955
|
var = condition.first_arg
|
|
936
956
|
env.current[var] = safe_literal(var.line)
|
|
937
|
-
|
|
957
|
+
process_if_branch branch
|
|
938
958
|
else
|
|
939
|
-
|
|
959
|
+
process_if_branch branch
|
|
940
960
|
end
|
|
941
961
|
branch_scopes << env.current
|
|
942
962
|
@branch_env = nil
|
|
@@ -953,6 +973,14 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
953
973
|
exp
|
|
954
974
|
end
|
|
955
975
|
|
|
976
|
+
def process_branch_with_value var, value, branch, branch_index
|
|
977
|
+
previous_value = env.current[var]
|
|
978
|
+
env.current[var] = value
|
|
979
|
+
result = process_if_branch branch
|
|
980
|
+
env.current[var] = previous_value
|
|
981
|
+
result
|
|
982
|
+
end
|
|
983
|
+
|
|
956
984
|
def early_return? exp
|
|
957
985
|
return true if node_type? exp, :return
|
|
958
986
|
return true if call? exp and [:fail, :raise].include? exp.method
|
|
@@ -1016,11 +1044,14 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
1016
1044
|
exp.each_sexp do |e|
|
|
1017
1045
|
if node_type? e, :when
|
|
1018
1046
|
scope do
|
|
1019
|
-
@branch_env = env.current
|
|
1020
|
-
|
|
1021
1047
|
# Process the when value for matching
|
|
1022
1048
|
process_default e[1]
|
|
1023
1049
|
|
|
1050
|
+
# Moved here to avoid @branch_env being cleared out
|
|
1051
|
+
# in process_default
|
|
1052
|
+
# Maybe in the future don't set it to nil?
|
|
1053
|
+
@branch_env = env.current
|
|
1054
|
+
|
|
1024
1055
|
# set value of case var if possible
|
|
1025
1056
|
if case_value
|
|
1026
1057
|
if simple_when? e
|
|
@@ -56,7 +56,7 @@ class Brakeman::GemProcessor < Brakeman::BasicProcessor
|
|
|
56
56
|
elsif exp.method == :ruby
|
|
57
57
|
version = exp.first_arg
|
|
58
58
|
if string? version
|
|
59
|
-
@tracker.config.set_ruby_version version.value
|
|
59
|
+
@tracker.config.set_ruby_version version.value, @gemfile, exp.line
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
elsif @inside_gemspec and exp.method == :add_dependency
|
|
@@ -97,7 +97,7 @@ class Brakeman::GemProcessor < Brakeman::BasicProcessor
|
|
|
97
97
|
if line =~ @gem_name_version
|
|
98
98
|
@tracker.config.add_gem $1, $2, file, line_num
|
|
99
99
|
elsif line =~ @ruby_version
|
|
100
|
-
@tracker.config.set_ruby_version $1
|
|
100
|
+
@tracker.config.set_ruby_version $1, file, line_num
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
103
|
end
|
data/lib/brakeman/rescanner.rb
CHANGED
|
@@ -6,7 +6,7 @@ require 'brakeman/differ'
|
|
|
6
6
|
class Brakeman::Rescanner < Brakeman::Scanner
|
|
7
7
|
include Brakeman::Util
|
|
8
8
|
KNOWN_TEMPLATE_EXTENSIONS = Brakeman::TemplateParser::KNOWN_TEMPLATE_EXTENSIONS
|
|
9
|
-
SCAN_ORDER = [:
|
|
9
|
+
SCAN_ORDER = [:gemfile, :config, :initializer, :lib, :routes, :template,
|
|
10
10
|
:model, :controller]
|
|
11
11
|
|
|
12
12
|
#Create new Rescanner to scan changed files
|
|
@@ -332,6 +332,8 @@ class Brakeman::Rescanner < Brakeman::Scanner
|
|
|
332
332
|
:routes
|
|
333
333
|
when /\/config\/.+\.(rb|yml)/
|
|
334
334
|
:config
|
|
335
|
+
when /\.ruby-version/
|
|
336
|
+
:config
|
|
335
337
|
when /Gemfile|gems\./
|
|
336
338
|
:gemfile
|
|
337
339
|
else
|
data/lib/brakeman/scanner.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
begin
|
|
2
2
|
Brakeman.load_brakeman_dependency 'ruby_parser'
|
|
3
|
-
Brakeman.load_brakeman_dependency 'ruby_parser/legacy'
|
|
4
3
|
require 'ruby_parser/bm_sexp.rb'
|
|
5
4
|
require 'ruby_parser/bm_sexp_processor.rb'
|
|
6
5
|
require 'brakeman/processor'
|
|
@@ -138,7 +137,7 @@ class Brakeman::Scanner
|
|
|
138
137
|
|
|
139
138
|
if @app_tree.exists? ".ruby-version"
|
|
140
139
|
if version = @app_tree.file_path(".ruby-version").read[/(\d\.\d.\d+)/]
|
|
141
|
-
tracker.config.set_ruby_version version
|
|
140
|
+
tracker.config.set_ruby_version version, @app_tree.file_path(".ruby-version"), 1
|
|
142
141
|
end
|
|
143
142
|
end
|
|
144
143
|
|
|
@@ -20,9 +20,7 @@ module Brakeman
|
|
|
20
20
|
|
|
21
21
|
def default_protect_from_forgery?
|
|
22
22
|
if version_between? "5.2.0.beta1", "9.9.9"
|
|
23
|
-
if @rails.dig(:action_controller, :default_protect_from_forgery) == Sexp.new(:
|
|
24
|
-
return false
|
|
25
|
-
else
|
|
23
|
+
if @rails.dig(:action_controller, :default_protect_from_forgery) == Sexp.new(:true)
|
|
26
24
|
return true
|
|
27
25
|
end
|
|
28
26
|
end
|
|
@@ -129,8 +127,9 @@ module Brakeman
|
|
|
129
127
|
@rails_version
|
|
130
128
|
end
|
|
131
129
|
|
|
132
|
-
def set_ruby_version version
|
|
130
|
+
def set_ruby_version version, file, line
|
|
133
131
|
@ruby_version = extract_version(version)
|
|
132
|
+
add_gem :ruby, @ruby_version, file, line
|
|
134
133
|
end
|
|
135
134
|
|
|
136
135
|
def extract_version version
|
|
@@ -230,6 +229,46 @@ module Brakeman
|
|
|
230
229
|
set_rails_config(value: true_value, path: [:active_storage, :replace_on_assign_to_many])
|
|
231
230
|
set_rails_config(value: true_value, path: [:active_record, :collection_cache_versioning])
|
|
232
231
|
end
|
|
232
|
+
|
|
233
|
+
if version >= 6.1
|
|
234
|
+
set_rails_config(value: true_value, path: [:action_controller, :urlsafe_csrf_tokens])
|
|
235
|
+
set_rails_config(value: Sexp.new(:lit, :lax), path: [:action_dispatch, :cookies_same_site_protection])
|
|
236
|
+
set_rails_config(value: Sexp.new(:lit, 308), path: [:action_dispatch, :ssl_default_redirect_status])
|
|
237
|
+
set_rails_config(value: false_value, path: [:action_view, :form_with_generates_remote_forms])
|
|
238
|
+
set_rails_config(value: true_value, path: [:action_view, :preload_links_header])
|
|
239
|
+
set_rails_config(value: Sexp.new(:lit, 0.15), path: [:active_job, :retry_jitter])
|
|
240
|
+
set_rails_config(value: true_value, path: [:active_record, :has_many_inversing])
|
|
241
|
+
set_rails_config(value: false_value, path: [:active_record, :legacy_connection_handling])
|
|
242
|
+
set_rails_config(value: true_value, path: [:active_storage, :track_variants])
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
if version >= 7.0
|
|
246
|
+
video_args =
|
|
247
|
+
Sexp.new(:str, "-vf 'select=eq(n\\,0)+eq(key\\,1)+gt(scene\\,0.015),loop=loop=-1:size=2,trim=start_frame=1' -frames:v 1 -f image2")
|
|
248
|
+
hash_class = s(:colon2, s(:colon2, s(:const, :OpenSSL), :Digest), :SHA256)
|
|
249
|
+
|
|
250
|
+
set_rails_config(value: true_value, path: [:action_controller, :raise_on_open_redirects])
|
|
251
|
+
set_rails_config(value: true_value, path: [:action_controller, :wrap_parameters_by_default])
|
|
252
|
+
set_rails_config(value: Sexp.new(:lit, :json), path: [:action_dispatch, :cookies_serializer])
|
|
253
|
+
set_rails_config(value: false_value, path: [:action_dispatch, :return_only_request_media_type_on_content_type])
|
|
254
|
+
set_rails_config(value: Sexp.new(:lit, 5), path: [:action_mailer, :smtp_timeout])
|
|
255
|
+
set_rails_config(value: false_value, path: [:action_view, :apply_stylesheet_media_default])
|
|
256
|
+
set_rails_config(value: true_value, path: [:ction_view, :button_to_generates_button_tag])
|
|
257
|
+
set_rails_config(value: true_value, path: [:active_record, :automatic_scope_inversing])
|
|
258
|
+
set_rails_config(value: false_value, path: [:active_record, :partial_inserts])
|
|
259
|
+
set_rails_config(value: true_value, path: [:active_record, :verify_foreign_keys_for_fixtures])
|
|
260
|
+
set_rails_config(value: true_value, path: [:active_storage, :multiple_file_field_include_hidden])
|
|
261
|
+
set_rails_config(value: Sexp.new(:lit, :vips), path: [:active_storage, :variant_processor])
|
|
262
|
+
set_rails_config(value: video_args, path: [:active_storage, :video_preview_arguments])
|
|
263
|
+
set_rails_config(value: Sexp.new(:lit, 7.0), path: [:active_support, :cache_format_version])
|
|
264
|
+
set_rails_config(value: true_value, path: [:active_support, :disable_to_s_conversion])
|
|
265
|
+
set_rails_config(value: true_value, path: [:active_support, :executor_around_test_case])
|
|
266
|
+
set_rails_config(value: hash_class, path: [:active_support, :hash_digest_class])
|
|
267
|
+
set_rails_config(value: Sexp.new(:lit, :thread), path: [:active_support, :isolation_level])
|
|
268
|
+
set_rails_config(value: hash_class, path: [:active_support, :key_generator_hash_digest_class])
|
|
269
|
+
set_rails_config(value: true_value, path: [:active_support, :remove_deprecated_time_with_zone_name])
|
|
270
|
+
set_rails_config(value: true_value, path: [:active_support, :use_rfc4122_namespaced_uuids])
|
|
271
|
+
end
|
|
233
272
|
end
|
|
234
273
|
end
|
|
235
274
|
end
|
data/lib/brakeman/tracker.rb
CHANGED
data/lib/brakeman/util.rb
CHANGED
|
@@ -265,15 +265,31 @@ module Brakeman::Util
|
|
|
265
265
|
false
|
|
266
266
|
end
|
|
267
267
|
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
# Only return true when accessing request headers via request.env[...]
|
|
269
|
+
def request_headers? exp
|
|
270
|
+
return unless sexp? exp
|
|
271
|
+
|
|
272
|
+
if exp[1] == REQUEST_ENV
|
|
273
|
+
if exp.method == :[]
|
|
274
|
+
if string? exp.first_arg
|
|
275
|
+
# Only care about HTTP headers, which are prefixed by 'HTTP_'
|
|
276
|
+
exp.first_arg.value.start_with?('HTTP_'.freeze)
|
|
277
|
+
else
|
|
278
|
+
true # request.env[something]
|
|
279
|
+
end
|
|
280
|
+
else
|
|
281
|
+
false # request.env.something
|
|
282
|
+
end
|
|
283
|
+
else
|
|
284
|
+
false
|
|
285
|
+
end
|
|
270
286
|
end
|
|
271
287
|
|
|
272
|
-
#Check if exp is params, cookies, or
|
|
288
|
+
#Check if exp is params, cookies, or request_headers
|
|
273
289
|
def request_value? exp
|
|
274
290
|
params? exp or
|
|
275
291
|
cookies? exp or
|
|
276
|
-
|
|
292
|
+
request_headers? exp
|
|
277
293
|
end
|
|
278
294
|
|
|
279
295
|
def constant? exp
|
data/lib/brakeman/version.rb
CHANGED
data/lib/brakeman.rb
CHANGED
|
@@ -493,10 +493,14 @@ module Brakeman
|
|
|
493
493
|
end
|
|
494
494
|
|
|
495
495
|
tracker = run(options)
|
|
496
|
+
new_report = JSON.parse(tracker.report.to_json, symbolize_names: true)
|
|
496
497
|
|
|
497
|
-
new_results =
|
|
498
|
+
new_results = new_report[:warnings]
|
|
499
|
+
obsolete_ignored = tracker.unused_fingerprints
|
|
498
500
|
|
|
499
|
-
Brakeman::Differ.new(new_results, previous_results).diff
|
|
501
|
+
Brakeman::Differ.new(new_results, previous_results).diff.tap do |diff|
|
|
502
|
+
diff[:obsolete] = obsolete_ignored
|
|
503
|
+
end
|
|
500
504
|
end
|
|
501
505
|
|
|
502
506
|
def self.load_brakeman_dependency name, allow_fail = false
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brakeman-lib
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 6.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Collins
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-05-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -94,20 +94,6 @@ dependencies:
|
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '3.19'
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: ruby_parser-legacy
|
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
|
100
|
-
requirements:
|
|
101
|
-
- - "~>"
|
|
102
|
-
- !ruby/object:Gem::Version
|
|
103
|
-
version: '1.0'
|
|
104
|
-
type: :runtime
|
|
105
|
-
prerelease: false
|
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
-
requirements:
|
|
108
|
-
- - "~>"
|
|
109
|
-
- !ruby/object:Gem::Version
|
|
110
|
-
version: '1.0'
|
|
111
97
|
- !ruby/object:Gem::Dependency
|
|
112
98
|
name: sexp_processor
|
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -450,7 +436,7 @@ metadata:
|
|
|
450
436
|
mailing_list_uri: https://gitter.im/presidentbeef/brakeman
|
|
451
437
|
source_code_uri: https://github.com/presidentbeef/brakeman
|
|
452
438
|
wiki_uri: https://github.com/presidentbeef/brakeman/wiki
|
|
453
|
-
post_install_message:
|
|
439
|
+
post_install_message:
|
|
454
440
|
rdoc_options: []
|
|
455
441
|
require_paths:
|
|
456
442
|
- lib
|
|
@@ -465,8 +451,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
465
451
|
- !ruby/object:Gem::Version
|
|
466
452
|
version: '0'
|
|
467
453
|
requirements: []
|
|
468
|
-
rubygems_version: 3.
|
|
469
|
-
signing_key:
|
|
454
|
+
rubygems_version: 3.2.3
|
|
455
|
+
signing_key:
|
|
470
456
|
specification_version: 4
|
|
471
457
|
summary: Security vulnerability scanner for Ruby on Rails.
|
|
472
458
|
test_files: []
|