brakeman-lib 4.2.1 → 4.3.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 +16 -0
- data/lib/brakeman.rb +4 -2
- data/lib/brakeman/checks/base_check.rb +4 -1
- data/lib/brakeman/checks/check_execute.rb +3 -2
- data/lib/brakeman/checks/check_link_to_href.rb +3 -2
- data/lib/brakeman/checks/check_sanitize_methods.rb +2 -8
- data/lib/brakeman/checks/check_sql.rb +1 -1
- data/lib/brakeman/codeclimate/engine_configuration.rb +2 -2
- data/lib/brakeman/file_parser.rb +5 -1
- data/lib/brakeman/options.rb +9 -1
- data/lib/brakeman/parsers/template_parser.rb +1 -1
- data/lib/brakeman/processors/alias_processor.rb +69 -1
- data/lib/brakeman/processors/lib/find_all_calls.rb +18 -5
- data/lib/brakeman/report/pager.rb +3 -1
- data/lib/brakeman/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08b3a1c2f84d6667c990309480405c61baa2f2ac878dfdc12dbefacdff64a52e'
|
4
|
+
data.tar.gz: 58ba877ea3b52c2e464bb4cca233edf1823f199db71e009df8eb92ce748ee9cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 905adec5711738aaddf2fbfd2bebd9ce9aa039a556fcacbef39177e1d34b44dd953952bf56904444211876466da5c16ae2c2bd8d42ebca00b6a7755a26e600de
|
7
|
+
data.tar.gz: da402133851cb1f3035cbe1784bf4c2e36831bd5167914c2bac82665b57430e2b9dbe9a4aa283e1365556dfcbfb07c933726049f9ee96377b83a676e56f1566f
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
# 4.3.0
|
2
|
+
|
3
|
+
* Check exec-type calls even if they are targets
|
4
|
+
* Convert `Array#join` to string interpolation
|
5
|
+
* `BaseCheck#include_interp?` should return first string interpolation
|
6
|
+
* Add `--parser-timeout` option
|
7
|
+
* Track parent calls in CallIndex
|
8
|
+
* Warn about dangerous `link_to` href with `sanitize()`
|
9
|
+
* Ignore `params#to_h` and `params#to_hash` in SQL checks
|
10
|
+
* Change "".freeze to just ""
|
11
|
+
* Ignore `Process.pid` in system calls
|
12
|
+
* Index Kernel#\` calls even if they are targets
|
13
|
+
* Code Climate: omit leading dot from `only_files` (Todd Mazierski)
|
14
|
+
* `--color` can be used to force color output
|
15
|
+
* Fix reported line numbers for CVE-2018-3741 and CVE-2018-8048
|
16
|
+
|
1
17
|
# 4.2.1
|
2
18
|
|
3
19
|
* Add warning for CVE-2018-3741
|
data/lib/brakeman.rb
CHANGED
@@ -51,6 +51,7 @@ module Brakeman
|
|
51
51
|
# * :output_files - files for output
|
52
52
|
# * :output_formats - formats for output (:to_s, :to_tabs, :to_csv, :to_html)
|
53
53
|
# * :parallel_checks - run checks in parallel (default: true)
|
54
|
+
# * :parser_timeout - set timeout for parsing an individual file (default: 10 seconds)
|
54
55
|
# * :print_report - if no output file specified, print to stdout (default: false)
|
55
56
|
# * :quiet - suppress most messages (default: true)
|
56
57
|
# * :rails3 - force Rails 3 mode (automatic)
|
@@ -174,6 +175,7 @@ module Brakeman
|
|
174
175
|
:output_color => true,
|
175
176
|
:pager => true,
|
176
177
|
:parallel_checks => true,
|
178
|
+
:parser_timeout => 10,
|
177
179
|
:relative_path => false,
|
178
180
|
:report_progress => true,
|
179
181
|
:safe_methods => Set.new,
|
@@ -376,7 +378,7 @@ module Brakeman
|
|
376
378
|
|
377
379
|
def self.write_report_to_files tracker, output_files
|
378
380
|
require 'fileutils'
|
379
|
-
tracker.options[:output_color] = false
|
381
|
+
tracker.options[:output_color] = false unless tracker.options[:output_color] == :force
|
380
382
|
|
381
383
|
output_files.each_with_index do |output_file, idx|
|
382
384
|
dir = File.dirname(output_file)
|
@@ -393,7 +395,7 @@ module Brakeman
|
|
393
395
|
private_class_method :write_report_to_files
|
394
396
|
|
395
397
|
def self.write_report_to_formats tracker, output_formats
|
396
|
-
unless $stdout.tty?
|
398
|
+
unless $stdout.tty? or tracker.options[:output_color] == :force
|
397
399
|
tracker.options[:output_color] = false
|
398
400
|
end
|
399
401
|
|
@@ -119,7 +119,10 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
119
119
|
|
120
120
|
#Does not actually process string interpolation, but notes that it occurred.
|
121
121
|
def process_dstr exp
|
122
|
-
@string_interp
|
122
|
+
unless @string_interp # don't overwrite existing value
|
123
|
+
@string_interp = Match.new(:interp, exp)
|
124
|
+
end
|
125
|
+
|
123
126
|
process_default exp
|
124
127
|
end
|
125
128
|
|
@@ -15,7 +15,8 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
15
15
|
|
16
16
|
SAFE_VALUES = [s(:const, :RAILS_ROOT),
|
17
17
|
s(:call, s(:const, :Rails), :root),
|
18
|
-
s(:call, s(:const, :Rails), :env)
|
18
|
+
s(:call, s(:const, :Rails), :env),
|
19
|
+
s(:call, s(:const, :Process), :pid)]
|
19
20
|
|
20
21
|
SHELL_ESCAPES = [:escape, :shellescape, :join]
|
21
22
|
|
@@ -32,7 +33,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
32
33
|
calls = tracker.find_call :targets => [:IO, :Open3, :Kernel, :'POSIX::Spawn', :Process, nil],
|
33
34
|
:methods => [:capture2, :capture2e, :capture3, :exec, :pipeline, :pipeline_r,
|
34
35
|
:pipeline_rw, :pipeline_start, :pipeline_w, :popen, :popen2, :popen2e,
|
35
|
-
:popen3, :spawn, :syscall, :system]
|
36
|
+
:popen3, :spawn, :syscall, :system], :nested => true
|
36
37
|
|
37
38
|
Brakeman.debug "Processing system calls"
|
38
39
|
calls.each do |result|
|
@@ -71,14 +71,15 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
CHECK_INSIDE_METHODS = [:url_for, :h, :sanitize]
|
75
|
+
|
74
76
|
def check_argument? url_arg
|
75
77
|
return unless call? url_arg
|
76
78
|
|
77
79
|
target = url_arg.target
|
78
80
|
method = url_arg.method
|
79
81
|
|
80
|
-
method
|
81
|
-
method == :h or
|
82
|
+
CHECK_INSIDE_METHODS.include? method or
|
82
83
|
cgi_escaped? target, method
|
83
84
|
end
|
84
85
|
|
@@ -46,12 +46,6 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
|
|
46
46
|
|
47
47
|
message = "Rails #{rails_version} has a vulnerability in #{method}: upgrade to #{@fix_version} or patch"
|
48
48
|
|
49
|
-
if include_user_input? result[:call]
|
50
|
-
confidence = :high
|
51
|
-
else
|
52
|
-
confidence = :medium
|
53
|
-
end
|
54
|
-
|
55
49
|
warn :result => result,
|
56
50
|
:warning_type => "Cross-Site Scripting",
|
57
51
|
:warning_code => code,
|
@@ -87,7 +81,7 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
|
|
87
81
|
warn :warning_type => "Cross-Site Scripting",
|
88
82
|
:warning_code => :CVE_2018_8048,
|
89
83
|
:message => message,
|
90
|
-
:gem_info => gemfile_or_environment,
|
84
|
+
:gem_info => gemfile_or_environment(:loofah),
|
91
85
|
:confidence => confidence,
|
92
86
|
:link_path => "https://github.com/flavorjones/loofah/issues/144"
|
93
87
|
end
|
@@ -111,7 +105,7 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
|
|
111
105
|
warn :warning_type => "Cross-Site Scripting",
|
112
106
|
:warning_code => cve.tr('-', '_').to_sym,
|
113
107
|
:message => message,
|
114
|
-
:gem_info => gemfile_or_environment,
|
108
|
+
:gem_info => gemfile_or_environment(:'rails-html-sanitizer'),
|
115
109
|
:confidence => confidence,
|
116
110
|
:link_path => link
|
117
111
|
end
|
@@ -290,7 +290,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
290
290
|
end
|
291
291
|
|
292
292
|
if request_value? arg
|
293
|
-
unless call? arg and params? arg.target and [:permit, :slice].include? arg.method
|
293
|
+
unless call? arg and params? arg.target and [:permit, :slice, :to_h, :to_hash].include? arg.method
|
294
294
|
# Model.where(params[:where])
|
295
295
|
arg
|
296
296
|
end
|
@@ -87,9 +87,9 @@ module Brakeman
|
|
87
87
|
|
88
88
|
def stripped_include_path(prefix, subprefixes, path)
|
89
89
|
if path.start_with?(prefix)
|
90
|
-
path.sub(%r{^#{prefix}/?}, "
|
90
|
+
path.sub(%r{^#{prefix}/?}, "/")
|
91
91
|
elsif subprefixes.any? { |subprefix| path =~ %r{^#{subprefix}/?$} }
|
92
|
-
"
|
92
|
+
"/"
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
data/lib/brakeman/file_parser.rb
CHANGED
@@ -7,6 +7,7 @@ module Brakeman
|
|
7
7
|
|
8
8
|
def initialize tracker, app_tree
|
9
9
|
@tracker = tracker
|
10
|
+
@timeout = @tracker.options[:parser_timeout]
|
10
11
|
@app_tree = app_tree
|
11
12
|
@file_list = {}
|
12
13
|
end
|
@@ -33,10 +34,13 @@ module Brakeman
|
|
33
34
|
def parse_ruby input, path
|
34
35
|
begin
|
35
36
|
Brakeman.debug "Parsing #{path}"
|
36
|
-
RubyParser.new.parse input, path
|
37
|
+
RubyParser.new.parse input, path, @timeout
|
37
38
|
rescue Racc::ParseError => e
|
38
39
|
@tracker.error e, "Could not parse #{path}"
|
39
40
|
nil
|
41
|
+
rescue Timeout::Error => e
|
42
|
+
@tracker.error Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout"), caller
|
43
|
+
nil
|
40
44
|
rescue => e
|
41
45
|
@tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
|
42
46
|
nil
|
data/lib/brakeman/options.rb
CHANGED
@@ -127,6 +127,10 @@ module Brakeman::Options
|
|
127
127
|
options[:branch_limit] = limit
|
128
128
|
end
|
129
129
|
|
130
|
+
opts.on "--parser-timeout SECONDS", Integer, "Set parse timeout (Default: 10)" do |timeout|
|
131
|
+
options[:parser_timeout] = timeout
|
132
|
+
end
|
133
|
+
|
130
134
|
opts.on "-r", "--report-direct", "Only report direct use of untrusted data" do |option|
|
131
135
|
options[:check_arguments] = !option
|
132
136
|
end
|
@@ -229,7 +233,11 @@ module Brakeman::Options
|
|
229
233
|
end
|
230
234
|
|
231
235
|
opts.on "--[no-]color", "Use ANSI colors in report (Default)" do |color|
|
232
|
-
|
236
|
+
if color
|
237
|
+
options[:output_color] = :force
|
238
|
+
else
|
239
|
+
options[:output_color] = color
|
240
|
+
end
|
233
241
|
end
|
234
242
|
|
235
243
|
opts.on "-m", "--routes", "Report controller information" do
|
@@ -93,7 +93,7 @@ module Brakeman
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def self.parse_inline_erb tracker, text
|
96
|
-
fp = Brakeman::FileParser.new(
|
96
|
+
fp = Brakeman::FileParser.new(tracker, nil)
|
97
97
|
tp = self.new(tracker, fp)
|
98
98
|
src = tp.parse_erb '_inline_', text
|
99
99
|
type = tp.erubis? ? :erubis : :erb
|
@@ -197,7 +197,6 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
197
197
|
return Sexp.new(:false)
|
198
198
|
end
|
199
199
|
|
200
|
-
|
201
200
|
#See if it is possible to simplify some basic cases
|
202
201
|
#of addition/concatenation.
|
203
202
|
case method
|
@@ -287,11 +286,80 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
287
286
|
if array? target and first_arg.nil? and sexp? target[1]
|
288
287
|
exp = target[1]
|
289
288
|
end
|
289
|
+
when :freeze
|
290
|
+
if string? target
|
291
|
+
exp = process exp.target
|
292
|
+
end
|
293
|
+
when :join
|
294
|
+
if array? target and target.length > 2 and (string? first_arg or first_arg.nil?)
|
295
|
+
exp = process_array_join(target, first_arg)
|
296
|
+
end
|
290
297
|
end
|
291
298
|
|
292
299
|
exp
|
293
300
|
end
|
294
301
|
|
302
|
+
# Painful conversion of Array#join into string interpolation
|
303
|
+
def process_array_join array, join_str
|
304
|
+
result = s()
|
305
|
+
|
306
|
+
join_value = if string? join_str
|
307
|
+
join_str.value
|
308
|
+
else
|
309
|
+
nil
|
310
|
+
end
|
311
|
+
|
312
|
+
array[1..-2].each do |e|
|
313
|
+
result << join_item(e, join_value)
|
314
|
+
end
|
315
|
+
|
316
|
+
result << join_item(array.last, nil)
|
317
|
+
|
318
|
+
# Combine the strings at the beginning because that's what RubyParser does
|
319
|
+
combined_first = ""
|
320
|
+
result.each do |e|
|
321
|
+
if string? e
|
322
|
+
combined_first << e.value
|
323
|
+
elsif e.is_a? String
|
324
|
+
combined_first << e
|
325
|
+
else
|
326
|
+
break
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
# Remove the strings at the beginning
|
331
|
+
result.reject! do |e|
|
332
|
+
if e.is_a? String or string? e
|
333
|
+
true
|
334
|
+
else
|
335
|
+
break
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
result.unshift combined_first
|
340
|
+
|
341
|
+
# Have to fix up strings that follow interpolation
|
342
|
+
result.reduce(s(:dstr)) do |memo, e|
|
343
|
+
if string? e and node_type? memo.last, :evstr
|
344
|
+
e.value = "#{join_value}#{e.value}"
|
345
|
+
elsif join_value and node_type? memo.last, :evstr and node_type? e, :evstr
|
346
|
+
memo << s(:str, join_value)
|
347
|
+
end
|
348
|
+
|
349
|
+
memo << e
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def join_item item, join_value
|
354
|
+
if item.is_a? String
|
355
|
+
"#{item}#{join_value}"
|
356
|
+
elsif string? item or symbol? item or number? item
|
357
|
+
s(:str, "#{item.value}#{join_value}")
|
358
|
+
else
|
359
|
+
s(:evstr, item)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
295
363
|
def process_iter exp
|
296
364
|
@exp_context.push exp
|
297
365
|
exp[1] = process exp.block_call
|
@@ -19,6 +19,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
|
|
19
19
|
@current_method = opts[:method]
|
20
20
|
@current_template = opts[:template]
|
21
21
|
@current_file = opts[:file]
|
22
|
+
@current_call = nil
|
22
23
|
process exp
|
23
24
|
end
|
24
25
|
|
@@ -111,7 +112,8 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
|
|
111
112
|
:method => method_name,
|
112
113
|
:call => exp,
|
113
114
|
:nested => false,
|
114
|
-
:location => make_location
|
115
|
+
:location => make_location,
|
116
|
+
:parent => @current_call }
|
115
117
|
end
|
116
118
|
|
117
119
|
#Gets the target of a call as a Symbol
|
@@ -189,7 +191,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
|
|
189
191
|
def create_call_hash exp
|
190
192
|
target = get_target exp.target
|
191
193
|
|
192
|
-
if call? target
|
194
|
+
if call? target or node_type? target, :dxstr # need to index `` even if target of a call
|
193
195
|
already_in_target = @in_target
|
194
196
|
@in_target = true
|
195
197
|
process target
|
@@ -199,13 +201,24 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
|
|
199
201
|
end
|
200
202
|
|
201
203
|
method = exp.method
|
202
|
-
process_call_args exp
|
203
204
|
|
204
|
-
|
205
|
+
call_hash = {
|
206
|
+
:target => target,
|
205
207
|
:method => method,
|
206
208
|
:call => exp,
|
207
209
|
:nested => @in_target,
|
208
210
|
:chain => get_chain(exp),
|
209
|
-
:location => make_location
|
211
|
+
:location => make_location,
|
212
|
+
:parent => @current_call
|
213
|
+
}
|
214
|
+
|
215
|
+
old_parent = @current_call
|
216
|
+
@current_call = call_hash
|
217
|
+
|
218
|
+
process_call_args exp
|
219
|
+
|
220
|
+
@current_call = old_parent
|
221
|
+
|
222
|
+
call_hash
|
210
223
|
end
|
211
224
|
end
|
@@ -102,7 +102,9 @@ module Brakeman
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def set_color
|
105
|
-
unless @tracker
|
105
|
+
return unless @tracker
|
106
|
+
|
107
|
+
unless less_options.include? "-R " or @tracker.options[:output_color] == :force
|
106
108
|
@tracker.options[:output_color] = false
|
107
109
|
end
|
108
110
|
end
|
data/lib/brakeman/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brakeman-lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.3.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: 2018-
|
12
|
+
date: 2018-05-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
@@ -380,7 +380,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
380
380
|
version: '0'
|
381
381
|
requirements: []
|
382
382
|
rubyforge_project:
|
383
|
-
rubygems_version: 2.7.
|
383
|
+
rubygems_version: 2.7.6
|
384
384
|
signing_key:
|
385
385
|
specification_version: 4
|
386
386
|
summary: Security vulnerability scanner for Ruby on Rails.
|