brakeman-lib 4.4.0 → 4.7.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 +63 -0
- data/README.md +6 -7
- data/lib/brakeman.rb +7 -0
- data/lib/brakeman/app_tree.rb +34 -22
- data/lib/brakeman/call_index.rb +54 -15
- data/lib/brakeman/checks.rb +7 -7
- data/lib/brakeman/checks/base_check.rb +75 -56
- data/lib/brakeman/checks/check_content_tag.rb +12 -0
- data/lib/brakeman/checks/check_cookie_serialization.rb +22 -0
- data/lib/brakeman/checks/check_cross_site_scripting.rb +15 -10
- data/lib/brakeman/checks/check_default_routes.rb +5 -0
- data/lib/brakeman/checks/check_deserialize.rb +49 -0
- data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
- data/lib/brakeman/checks/check_evaluation.rb +0 -1
- data/lib/brakeman/checks/check_execute.rb +44 -1
- data/lib/brakeman/checks/check_file_access.rb +7 -1
- data/lib/brakeman/checks/check_force_ssl.rb +27 -0
- 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 +7 -2
- data/lib/brakeman/checks/check_link_to_href.rb +6 -1
- data/lib/brakeman/checks/check_mail_to.rb +1 -1
- data/lib/brakeman/checks/check_mime_type_dos.rb +2 -2
- data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
- data/lib/brakeman/checks/check_model_attributes.rb +12 -50
- data/lib/brakeman/checks/check_model_serialize.rb +1 -1
- data/lib/brakeman/checks/check_nested_attributes_bypass.rb +4 -4
- data/lib/brakeman/checks/check_reverse_tabnabbing.rb +54 -0
- data/lib/brakeman/checks/check_sanitize_methods.rb +2 -2
- data/lib/brakeman/checks/check_secrets.rb +1 -1
- data/lib/brakeman/checks/check_send.rb +0 -1
- data/lib/brakeman/checks/check_session_manipulation.rb +0 -1
- data/lib/brakeman/checks/check_session_settings.rb +15 -12
- data/lib/brakeman/checks/check_simple_format.rb +5 -0
- data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
- data/lib/brakeman/checks/check_sql.rb +27 -20
- data/lib/brakeman/checks/check_validation_regex.rb +1 -1
- 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 +6 -8
- data/lib/brakeman/file_path.rb +85 -0
- data/lib/brakeman/options.rb +7 -0
- data/lib/brakeman/parsers/haml_embedded.rb +44 -0
- data/lib/brakeman/parsers/slim_embedded.rb +44 -0
- data/lib/brakeman/parsers/template_parser.rb +8 -8
- data/lib/brakeman/processor.rb +4 -5
- data/lib/brakeman/processors/alias_processor.rb +49 -7
- data/lib/brakeman/processors/base_processor.rb +10 -7
- data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
- data/lib/brakeman/processors/controller_processor.rb +9 -13
- data/lib/brakeman/processors/gem_processor.rb +10 -2
- data/lib/brakeman/processors/haml_template_processor.rb +92 -123
- data/lib/brakeman/processors/lib/call_conversion_helper.rb +4 -0
- 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/module_helper.rb +8 -8
- data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +4 -4
- data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
- data/lib/brakeman/processors/lib/render_helper.rb +2 -2
- data/lib/brakeman/processors/lib/render_path.rb +18 -1
- data/lib/brakeman/processors/library_processor.rb +5 -5
- data/lib/brakeman/processors/model_processor.rb +4 -5
- data/lib/brakeman/processors/output_processor.rb +5 -0
- data/lib/brakeman/processors/slim_template_processor.rb +16 -0
- data/lib/brakeman/processors/template_alias_processor.rb +32 -5
- data/lib/brakeman/processors/template_processor.rb +14 -10
- data/lib/brakeman/report.rb +3 -3
- data/lib/brakeman/report/ignore/config.rb +2 -3
- data/lib/brakeman/report/ignore/interactive.rb +2 -2
- data/lib/brakeman/report/pager.rb +1 -0
- data/lib/brakeman/report/report_base.rb +51 -6
- data/lib/brakeman/report/report_codeclimate.rb +3 -3
- data/lib/brakeman/report/report_hash.rb +1 -1
- data/lib/brakeman/report/report_html.rb +2 -2
- data/lib/brakeman/report/report_json.rb +1 -24
- data/lib/brakeman/report/report_table.rb +20 -4
- data/lib/brakeman/report/report_tabs.rb +1 -1
- data/lib/brakeman/report/report_text.rb +2 -2
- data/lib/brakeman/rescanner.rb +13 -12
- data/lib/brakeman/scanner.rb +24 -18
- data/lib/brakeman/tracker.rb +35 -7
- data/lib/brakeman/tracker/collection.rb +4 -3
- data/lib/brakeman/tracker/config.rb +44 -48
- data/lib/brakeman/tracker/constants.rb +2 -1
- data/lib/brakeman/util.rb +18 -147
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +27 -13
- data/lib/brakeman/warning_codes.rb +4 -0
- data/lib/ruby_parser/bm_sexp.rb +1 -1
- data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
- metadata +58 -43
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e29d6575b47438b336589ce753da72098ad1b7465a4bb78625d5c666d8c1d0a3
|
|
4
|
+
data.tar.gz: 073d249eb7c1915c3c3be01345c25d050127eec929ff2dd77e276433f94606c1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 87488f856d5b69554147a900ea4a5e0f8826b8a4a1ca95090c472f279d3014a80d28acfa36e131b07c2a9d78a80ec807fa20b45f7e2c133575da164b8ccf3506
|
|
7
|
+
data.tar.gz: b73fe208fc26c26428b4883aa36e2b0c310f7b271fe9db0111cd5fc23d3fc040b8f90c0875f4736724685515ee6c3a6d20faf4cb1246042fab0fe66a6de41c61
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,66 @@
|
|
|
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
|
+
|
|
12
|
+
# 4.6.1
|
|
13
|
+
|
|
14
|
+
* Fix Reverse Tabnabbing warning message (Steffen Schildknecht / Jörg Schiller)
|
|
15
|
+
|
|
16
|
+
# 4.6.0
|
|
17
|
+
|
|
18
|
+
* Skip calls to `dup`
|
|
19
|
+
* Add reverse tabnabbing check (Linos Giannopoulos)
|
|
20
|
+
* Better handling of gems with no version declared
|
|
21
|
+
* Warn people that Haml 5 is not fully supported (Jared Beck)
|
|
22
|
+
* Avoid warning about file access with `ActiveStorage::Filename#sanitized` (Tejas Bubane)
|
|
23
|
+
* Update loofah version for fixing CVE-2018-8048 (Markus Nölle)
|
|
24
|
+
* Restore `Warning#relative_path`
|
|
25
|
+
* Add check for cookie serialization with Marshal
|
|
26
|
+
* Index calls in initializers
|
|
27
|
+
* Improve template output handling in conditional branches
|
|
28
|
+
* Avoid assigning `nil` line numbers to `Sexp`s
|
|
29
|
+
* Add special warning code for custom checks
|
|
30
|
+
* Add call matching by regular expression
|
|
31
|
+
|
|
32
|
+
# 4.5.1
|
|
33
|
+
|
|
34
|
+
* Add `Brakeman::FilePath` to represent file paths
|
|
35
|
+
* Handle trailing comma in block args
|
|
36
|
+
* Properly handle empty partial name
|
|
37
|
+
* Use relative paths for `__FILE__`
|
|
38
|
+
* Convert `!!` calls to boolean value
|
|
39
|
+
* Add optional check for `config.force_ssl`
|
|
40
|
+
* Remove code for Ruby versions prior to 1.9
|
|
41
|
+
* Check `link_to` with block for href XSS
|
|
42
|
+
* Add SQL injection checks for `find_or_create_by` and friends
|
|
43
|
+
* Add deserialization warning for `Oj.load/object_load`
|
|
44
|
+
* Add initial Rails 6 support
|
|
45
|
+
* Add SQL injection checks for `destroy_by`/`delete_by`
|
|
46
|
+
|
|
47
|
+
# 4.5.0
|
|
48
|
+
|
|
49
|
+
* Update `ruby_parser`, use `ruby_parser-legacy`
|
|
50
|
+
* More thoroughly handle `Shellwords` escaping
|
|
51
|
+
* Handle non-integer version number comparisons
|
|
52
|
+
* Use `FileParser` in `Scanner` to parse files
|
|
53
|
+
* Add original exception to `Tracker#errors` list
|
|
54
|
+
* Add support for CoffeeScript in Slim templates
|
|
55
|
+
* Improve support for embedded template "filters"
|
|
56
|
+
* Remove Sass dependency
|
|
57
|
+
* Set location information in `CheckContentTag`
|
|
58
|
+
* Stop swallowing exceptions in `AliasProcessor`
|
|
59
|
+
* Avoid joining strings with different encodings
|
|
60
|
+
* Handle `**` inside Hash literals
|
|
61
|
+
* Better handling of splat/kwsplat arguments
|
|
62
|
+
* Improve "user input" reported for SQL injection
|
|
63
|
+
|
|
1
64
|
# 4.4.0
|
|
2
65
|
|
|
3
66
|
* Set default encoding to UTF-8
|
data/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
[](http://brakemanscanner.org/)
|
|
2
2
|
|
|
3
|
-
[](https://codeclimate.com/github/presidentbeef/brakeman/maintainability)
|
|
3
|
+
[](https://circleci.com/gh/presidentbeef/brakeman)
|
|
5
4
|
[](https://codeclimate.com/github/presidentbeef/brakeman/test_coverage)
|
|
6
5
|
[](https://gitter.im/presidentbeef/brakeman)
|
|
7
6
|
|
|
@@ -47,25 +46,25 @@ Outside of Rails root:
|
|
|
47
46
|
|
|
48
47
|
From a Rails application's root directory:
|
|
49
48
|
|
|
50
|
-
docker run -v "$(pwd)":/code brakeman
|
|
49
|
+
docker run -v "$(pwd)":/code presidentbeef/brakeman
|
|
51
50
|
|
|
52
51
|
With a little nicer color:
|
|
53
52
|
|
|
54
|
-
docker run -v "$(pwd)":/code brakeman --color
|
|
53
|
+
docker run -v "$(pwd)":/code presidentbeef/brakeman --color
|
|
55
54
|
|
|
56
55
|
For an HTML report:
|
|
57
56
|
|
|
58
|
-
docker run -v "$(pwd)":/code brakeman -o brakeman_results.html
|
|
57
|
+
docker run -v "$(pwd)":/code presidentbeef/brakeman -o brakeman_results.html
|
|
59
58
|
|
|
60
59
|
Outside of Rails root (note that the output file is relative to path/to/rails/application):
|
|
61
60
|
|
|
62
|
-
docker run -v 'path/to/rails/application':/code brakeman -o brakeman_results.html
|
|
61
|
+
docker run -v 'path/to/rails/application':/code presidentbeef/brakeman -o brakeman_results.html
|
|
63
62
|
|
|
64
63
|
# Compatibility
|
|
65
64
|
|
|
66
65
|
Brakeman should work with any version of Rails from 2.3.x to 5.x.
|
|
67
66
|
|
|
68
|
-
Brakeman can analyze code written with Ruby 1.8 syntax and newer, but requires at least Ruby
|
|
67
|
+
Brakeman can analyze code written with Ruby 1.8 syntax and newer, but requires at least Ruby 2.3.0 to run.
|
|
69
68
|
|
|
70
69
|
# Basic Options
|
|
71
70
|
|
data/lib/brakeman.rb
CHANGED
|
@@ -55,6 +55,9 @@ module Brakeman
|
|
|
55
55
|
# * :print_report - if no output file specified, print to stdout (default: false)
|
|
56
56
|
# * :quiet - suppress most messages (default: true)
|
|
57
57
|
# * :rails3 - force Rails 3 mode (automatic)
|
|
58
|
+
# * :rails4 - force Rails 4 mode (automatic)
|
|
59
|
+
# * :rails5 - force Rails 5 mode (automatic)
|
|
60
|
+
# * :rails6 - force Rails 6 mode (automatic)
|
|
58
61
|
# * :report_routes - show found routes on controllers (default: false)
|
|
59
62
|
# * :run_checks - array of checks to run (run all if not specified)
|
|
60
63
|
# * :safe_methods - array of methods to consider safe
|
|
@@ -99,6 +102,10 @@ module Brakeman
|
|
|
99
102
|
elsif options[:rails5]
|
|
100
103
|
options[:rails3] = true
|
|
101
104
|
options[:rails4] = true
|
|
105
|
+
elsif options[:rails6]
|
|
106
|
+
options[:rails3] = true
|
|
107
|
+
options[:rails4] = true
|
|
108
|
+
options[:rails5] = true
|
|
102
109
|
end
|
|
103
110
|
|
|
104
111
|
options[:output_formats] = get_output_formats options
|
data/lib/brakeman/app_tree.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'pathname'
|
|
2
|
+
require 'brakeman/file_path'
|
|
2
3
|
|
|
3
4
|
module Brakeman
|
|
4
5
|
class AppTree
|
|
@@ -62,31 +63,37 @@ module Brakeman
|
|
|
62
63
|
@absolute_engine_paths = @engine_paths.select { |path| path.start_with?(File::SEPARATOR) }
|
|
63
64
|
@relative_engine_paths = @engine_paths - @absolute_engine_paths
|
|
64
65
|
@gemspec = nil
|
|
66
|
+
@root_search_pattern = nil
|
|
65
67
|
end
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
# Create a new Brakeman::FilePath
|
|
70
|
+
def file_path(path)
|
|
71
|
+
Brakeman::FilePath.from_app_tree(self, path)
|
|
69
72
|
end
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
# Should only be used by Brakeman::FilePath.
|
|
75
|
+
# Use AppTree#file_path(path).absolute instead.
|
|
76
|
+
def expand_path(path)
|
|
77
|
+
File.expand_path(path, @root)
|
|
73
78
|
end
|
|
74
79
|
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
# Should only be used by Brakeman::FilePath
|
|
81
|
+
# Use AppTree#file_path(path).relative instead.
|
|
82
|
+
def relative_path(path)
|
|
83
|
+
pname = Pathname.new path
|
|
84
|
+
if path and not path.empty? and pname.absolute?
|
|
85
|
+
pname.relative_path_from(Pathname.new(self.root)).to_s
|
|
86
|
+
else
|
|
87
|
+
path
|
|
88
|
+
end
|
|
81
89
|
end
|
|
82
90
|
|
|
83
91
|
def exists?(path)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
File.exist?(path)
|
|
92
|
+
if path.is_a? Brakeman::FilePath
|
|
93
|
+
path.exists?
|
|
94
|
+
else
|
|
95
|
+
File.exist?(File.join(@root, path))
|
|
96
|
+
end
|
|
90
97
|
end
|
|
91
98
|
|
|
92
99
|
def initializer_paths
|
|
@@ -111,7 +118,7 @@ module Brakeman
|
|
|
111
118
|
end
|
|
112
119
|
|
|
113
120
|
def lib_paths
|
|
114
|
-
@lib_files ||= find_paths("lib").reject { |path| path.include? "/generators/" or path.include? "lib/tasks/" or path.include? "lib/templates/" } +
|
|
121
|
+
@lib_files ||= find_paths("lib").reject { |path| path.relative.include? "/generators/" or path.relative.include? "lib/tasks/" or path.relative.include? "lib/templates/" } +
|
|
115
122
|
find_additional_lib_paths +
|
|
116
123
|
find_helper_paths +
|
|
117
124
|
find_job_paths
|
|
@@ -125,7 +132,7 @@ module Brakeman
|
|
|
125
132
|
if gemspecs.length > 1 or gemspecs.empty?
|
|
126
133
|
@gemspec = false
|
|
127
134
|
else
|
|
128
|
-
@gemspec = File.basename(gemspecs.first)
|
|
135
|
+
@gemspec = file_path(File.basename(gemspecs.first))
|
|
129
136
|
end
|
|
130
137
|
end
|
|
131
138
|
|
|
@@ -155,7 +162,8 @@ module Brakeman
|
|
|
155
162
|
|
|
156
163
|
def select_files(paths)
|
|
157
164
|
paths = select_only_files(paths)
|
|
158
|
-
reject_skipped_files(paths)
|
|
165
|
+
paths = reject_skipped_files(paths)
|
|
166
|
+
convert_to_file_paths(paths)
|
|
159
167
|
end
|
|
160
168
|
|
|
161
169
|
def select_only_files(paths)
|
|
@@ -190,8 +198,8 @@ module Brakeman
|
|
|
190
198
|
def root_search_pattern
|
|
191
199
|
return @root_search_pattern if @root_search_pattern
|
|
192
200
|
|
|
193
|
-
abs = @absolute_engine_paths.to_a.map { |path| path.gsub
|
|
194
|
-
rel = @relative_engine_paths.to_a.map { |path| path.gsub
|
|
201
|
+
abs = @absolute_engine_paths.to_a.map { |path| path.gsub(/#{File::SEPARATOR}+$/, '') }
|
|
202
|
+
rel = @relative_engine_paths.to_a.map { |path| path.gsub(/#{File::SEPARATOR}+$/, '') }
|
|
195
203
|
|
|
196
204
|
roots = ([@root] + abs).join(",")
|
|
197
205
|
rel_engines = (rel + [""]).join("/,")
|
|
@@ -199,7 +207,11 @@ module Brakeman
|
|
|
199
207
|
end
|
|
200
208
|
|
|
201
209
|
def prioritize_concerns paths
|
|
202
|
-
paths.partition { |path| path.include? "concerns" }.flatten
|
|
210
|
+
paths.partition { |path| path.relative.include? "concerns" }.flatten
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def convert_to_file_paths paths
|
|
214
|
+
paths.map { |path| file_path(path) }
|
|
203
215
|
end
|
|
204
216
|
end
|
|
205
217
|
end
|
data/lib/brakeman/call_index.rb
CHANGED
|
@@ -27,7 +27,7 @@ class Brakeman::CallIndex
|
|
|
27
27
|
if options[:chained]
|
|
28
28
|
return find_chain options
|
|
29
29
|
#Find by narrowest category
|
|
30
|
-
elsif target
|
|
30
|
+
elsif target.is_a? Array and method.is_a? Array
|
|
31
31
|
if target.length > method.length
|
|
32
32
|
calls = filter_by_target calls_by_methods(method), target
|
|
33
33
|
else
|
|
@@ -35,6 +35,12 @@ class Brakeman::CallIndex
|
|
|
35
35
|
calls = filter_by_method calls, method
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
elsif target.is_a? Regexp and method
|
|
39
|
+
calls = filter_by_target(calls_by_method(method), target)
|
|
40
|
+
|
|
41
|
+
elsif method.is_a? Regexp and target
|
|
42
|
+
calls = filter_by_method(calls_by_target(target), method)
|
|
43
|
+
|
|
38
44
|
#Find by target, then by methods, if provided
|
|
39
45
|
elsif target
|
|
40
46
|
calls = calls_by_target target
|
|
@@ -85,6 +91,16 @@ class Brakeman::CallIndex
|
|
|
85
91
|
end
|
|
86
92
|
end
|
|
87
93
|
|
|
94
|
+
def remove_indexes_by_file file
|
|
95
|
+
[@calls_by_method, @calls_by_target].each do |calls_by|
|
|
96
|
+
calls_by.each do |_name, calls|
|
|
97
|
+
calls.delete_if do |call|
|
|
98
|
+
call[:location][:file] == file
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
88
104
|
def index_calls calls
|
|
89
105
|
calls.each do |call|
|
|
90
106
|
@calls_by_method[call[:method]] ||= []
|
|
@@ -116,8 +132,11 @@ class Brakeman::CallIndex
|
|
|
116
132
|
end
|
|
117
133
|
|
|
118
134
|
def calls_by_target target
|
|
119
|
-
|
|
135
|
+
case target
|
|
136
|
+
when Array
|
|
120
137
|
calls_by_targets target
|
|
138
|
+
when Regexp
|
|
139
|
+
calls_by_targets_regex target
|
|
121
140
|
else
|
|
122
141
|
@calls_by_target[target] || []
|
|
123
142
|
end
|
|
@@ -133,10 +152,24 @@ class Brakeman::CallIndex
|
|
|
133
152
|
calls
|
|
134
153
|
end
|
|
135
154
|
|
|
155
|
+
def calls_by_targets_regex targets_regex
|
|
156
|
+
calls = []
|
|
157
|
+
|
|
158
|
+
@calls_by_target.each do |key, value|
|
|
159
|
+
case key
|
|
160
|
+
when String, Symbol
|
|
161
|
+
calls.concat value if key.match targets_regex
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
calls
|
|
166
|
+
end
|
|
167
|
+
|
|
136
168
|
def calls_by_method method
|
|
137
|
-
|
|
169
|
+
case method
|
|
170
|
+
when Array
|
|
138
171
|
calls_by_methods method
|
|
139
|
-
|
|
172
|
+
when Regexp
|
|
140
173
|
calls_by_methods_regex method
|
|
141
174
|
else
|
|
142
175
|
@calls_by_method[method.to_sym] || []
|
|
@@ -156,26 +189,28 @@ class Brakeman::CallIndex
|
|
|
156
189
|
|
|
157
190
|
def calls_by_methods_regex methods_regex
|
|
158
191
|
calls = []
|
|
192
|
+
|
|
159
193
|
@calls_by_method.each do |key, value|
|
|
160
|
-
calls.concat value if key.
|
|
194
|
+
calls.concat value if key.match methods_regex
|
|
161
195
|
end
|
|
162
|
-
calls
|
|
163
|
-
end
|
|
164
196
|
|
|
165
|
-
|
|
166
|
-
@calls_by_target[nil]
|
|
197
|
+
calls
|
|
167
198
|
end
|
|
168
199
|
|
|
169
200
|
def filter calls, key, value
|
|
170
|
-
|
|
201
|
+
case value
|
|
202
|
+
when Array
|
|
171
203
|
values = Set.new value
|
|
172
204
|
|
|
173
205
|
calls.select do |call|
|
|
174
206
|
values.include? call[key]
|
|
175
207
|
end
|
|
176
|
-
|
|
208
|
+
when Regexp
|
|
177
209
|
calls.select do |call|
|
|
178
|
-
call[key]
|
|
210
|
+
case call[key]
|
|
211
|
+
when String, Symbol
|
|
212
|
+
call[key].match value
|
|
213
|
+
end
|
|
179
214
|
end
|
|
180
215
|
else
|
|
181
216
|
calls.select do |call|
|
|
@@ -197,15 +232,19 @@ class Brakeman::CallIndex
|
|
|
197
232
|
end
|
|
198
233
|
|
|
199
234
|
def filter_by_chain calls, target
|
|
200
|
-
|
|
235
|
+
case target
|
|
236
|
+
when Array
|
|
201
237
|
targets = Set.new target
|
|
202
238
|
|
|
203
239
|
calls.select do |call|
|
|
204
240
|
targets.include? call[:chain].first
|
|
205
241
|
end
|
|
206
|
-
|
|
242
|
+
when Regexp
|
|
207
243
|
calls.select do |call|
|
|
208
|
-
call[:chain].first
|
|
244
|
+
case call[:chain].first
|
|
245
|
+
when String, Symbol
|
|
246
|
+
call[:chain].first.match target
|
|
247
|
+
end
|
|
209
248
|
end
|
|
210
249
|
else
|
|
211
250
|
calls.select do |call|
|
data/lib/brakeman/checks.rb
CHANGED
|
@@ -109,13 +109,13 @@ class Brakeman::Checks
|
|
|
109
109
|
|
|
110
110
|
#Run all the checks on the given Tracker.
|
|
111
111
|
#Returns a new instance of Checks with the results.
|
|
112
|
-
def self.run_checks(
|
|
112
|
+
def self.run_checks(tracker)
|
|
113
113
|
checks = self.checks_to_run(tracker)
|
|
114
114
|
check_runner = self.new :min_confidence => tracker.options[:min_confidence]
|
|
115
|
-
self.actually_run_checks(checks, check_runner,
|
|
115
|
+
self.actually_run_checks(checks, check_runner, tracker)
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
def self.actually_run_checks(checks, check_runner,
|
|
118
|
+
def self.actually_run_checks(checks, check_runner, tracker)
|
|
119
119
|
threads = [] # Results for parallel
|
|
120
120
|
results = [] # Results for sequential
|
|
121
121
|
parallel = tracker.options[:parallel_checks]
|
|
@@ -127,10 +127,10 @@ class Brakeman::Checks
|
|
|
127
127
|
|
|
128
128
|
if parallel
|
|
129
129
|
threads << Thread.new do
|
|
130
|
-
self.run_a_check(c, error_mutex,
|
|
130
|
+
self.run_a_check(c, error_mutex, tracker)
|
|
131
131
|
end
|
|
132
132
|
else
|
|
133
|
-
results << self.run_a_check(c, error_mutex,
|
|
133
|
+
results << self.run_a_check(c, error_mutex, tracker)
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
#Maintain list of which checks were run
|
|
@@ -196,8 +196,8 @@ class Brakeman::Checks
|
|
|
196
196
|
end
|
|
197
197
|
end
|
|
198
198
|
|
|
199
|
-
def self.run_a_check klass, mutex,
|
|
200
|
-
check = klass.new(
|
|
199
|
+
def self.run_a_check klass, mutex, tracker
|
|
200
|
+
check = klass.new(tracker)
|
|
201
201
|
|
|
202
202
|
begin
|
|
203
203
|
check.run_check
|
|
@@ -27,9 +27,9 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
#Initialize Check with Checks.
|
|
30
|
-
def initialize(
|
|
30
|
+
def initialize(tracker)
|
|
31
31
|
super()
|
|
32
|
-
@app_tree = app_tree
|
|
32
|
+
@app_tree = tracker.app_tree
|
|
33
33
|
@results = [] #only to check for duplicates
|
|
34
34
|
@warnings = []
|
|
35
35
|
@tracker = tracker
|
|
@@ -39,24 +39,15 @@ 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
|
|
45
46
|
|
|
46
47
|
#Add result to result list, which is used to check for duplicates
|
|
47
|
-
def add_result result
|
|
48
|
-
location
|
|
49
|
-
location =
|
|
50
|
-
location = location.name if location.is_a? Brakeman::Collection
|
|
51
|
-
location = location.to_sym
|
|
52
|
-
|
|
53
|
-
if result.is_a? Hash
|
|
54
|
-
line = result[:call].original_line || result[:call].line
|
|
55
|
-
elsif sexp? result
|
|
56
|
-
line = result.original_line || result.line
|
|
57
|
-
else
|
|
58
|
-
raise ArgumentError
|
|
59
|
-
end
|
|
48
|
+
def add_result result
|
|
49
|
+
location = get_location result
|
|
50
|
+
location, line = get_location result
|
|
60
51
|
|
|
61
52
|
@results << [line, location, result]
|
|
62
53
|
end
|
|
@@ -119,9 +110,16 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
119
110
|
exp
|
|
120
111
|
end
|
|
121
112
|
|
|
113
|
+
def process_array exp
|
|
114
|
+
@in_array = true
|
|
115
|
+
process_default exp
|
|
116
|
+
ensure
|
|
117
|
+
@in_array = false
|
|
118
|
+
end
|
|
119
|
+
|
|
122
120
|
#Does not actually process string interpolation, but notes that it occurred.
|
|
123
121
|
def process_dstr exp
|
|
124
|
-
unless @string_interp # don't overwrite existing value
|
|
122
|
+
unless array_interp? exp or @string_interp # don't overwrite existing value
|
|
125
123
|
@string_interp = Match.new(:interp, exp)
|
|
126
124
|
end
|
|
127
125
|
|
|
@@ -130,6 +128,20 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
130
128
|
|
|
131
129
|
private
|
|
132
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
|
+
|
|
133
145
|
def always_safe_method? meth
|
|
134
146
|
@safe_input_attributes.include? meth or
|
|
135
147
|
@comparison_ops.include? meth
|
|
@@ -143,11 +155,11 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
143
155
|
def warn options
|
|
144
156
|
extra_opts = { :check => self.class.to_s }
|
|
145
157
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
158
|
+
if options[:file]
|
|
159
|
+
options[:file] = @app_tree.file_path(options[:file])
|
|
160
|
+
end
|
|
149
161
|
|
|
150
|
-
@warnings <<
|
|
162
|
+
@warnings << Brakeman::Warning.new(options.merge(extra_opts))
|
|
151
163
|
end
|
|
152
164
|
|
|
153
165
|
#Run _exp_ through OutputProcessor to get a nice String.
|
|
@@ -170,8 +182,9 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
170
182
|
@mass_assign_disabled = true
|
|
171
183
|
else
|
|
172
184
|
#Check for ActiveRecord::Base.send(:attr_accessible, nil)
|
|
173
|
-
tracker.
|
|
174
|
-
call = result
|
|
185
|
+
tracker.find_call(target: :"ActiveRecord::Base", method: :attr_accessible).each do |result|
|
|
186
|
+
call = result[:call]
|
|
187
|
+
|
|
175
188
|
if call? call
|
|
176
189
|
if call.first_arg == Sexp.new(:nil)
|
|
177
190
|
@mass_assign_disabled = true
|
|
@@ -180,26 +193,12 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
180
193
|
end
|
|
181
194
|
end
|
|
182
195
|
|
|
183
|
-
unless @mass_assign_disabled
|
|
184
|
-
tracker.check_initializers(:"ActiveRecord::Base", :send).each do |result|
|
|
185
|
-
call = result.call
|
|
186
|
-
if call? call
|
|
187
|
-
if call.first_arg == Sexp.new(:lit, :attr_accessible) and call.second_arg == Sexp.new(:nil)
|
|
188
|
-
@mass_assign_disabled = true
|
|
189
|
-
break
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
|
|
195
196
|
unless @mass_assign_disabled
|
|
196
197
|
#Check for
|
|
197
198
|
# class ActiveRecord::Base
|
|
198
199
|
# attr_accessible nil
|
|
199
200
|
# end
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
matches.each do |result|
|
|
201
|
+
tracker.check_initializers([], :attr_accessible).each do |result|
|
|
203
202
|
if result.module == "ActiveRecord" and result.result_class == :Base
|
|
204
203
|
arg = result.call.first_arg
|
|
205
204
|
|
|
@@ -227,10 +226,8 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
227
226
|
end
|
|
228
227
|
|
|
229
228
|
unless @mass_assign_disabled
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
matches.each do |result|
|
|
233
|
-
call = result.call
|
|
229
|
+
tracker.find_call(target: :"ActiveRecord::Base", method: [:send, :include]).each do |result|
|
|
230
|
+
call = result[:call]
|
|
234
231
|
if call? call and (call.first_arg == forbidden_protection or call.second_arg == forbidden_protection)
|
|
235
232
|
@mass_assign_disabled = true
|
|
236
233
|
end
|
|
@@ -250,6 +247,22 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
250
247
|
#This is to avoid reporting duplicates. Checks if the result has been
|
|
251
248
|
#reported already from the same line number.
|
|
252
249
|
def duplicate? result, location = nil
|
|
250
|
+
location, line = get_location result
|
|
251
|
+
|
|
252
|
+
@results.each do |r|
|
|
253
|
+
if r[0] == line and r[1] == location
|
|
254
|
+
if tracker.options[:combine_locations]
|
|
255
|
+
return true
|
|
256
|
+
elsif r[2] == result
|
|
257
|
+
return true
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
false
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def get_location result
|
|
253
266
|
if result.is_a? Hash
|
|
254
267
|
line = result[:call].original_line || result[:call].line
|
|
255
268
|
elsif sexp? result
|
|
@@ -258,23 +271,13 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
258
271
|
raise ArgumentError
|
|
259
272
|
end
|
|
260
273
|
|
|
261
|
-
location ||= (@current_template && @current_template.name) || @current_class || @current_module || @current_set || result[:location][:class] || result[:location][:template]
|
|
274
|
+
location ||= (@current_template && @current_template.name) || @current_class || @current_module || @current_set || result[:location][:class] || result[:location][:template] || result[:location][:file].to_s
|
|
262
275
|
|
|
263
276
|
location = location[:name] if location.is_a? Hash
|
|
264
277
|
location = location.name if location.is_a? Brakeman::Collection
|
|
265
278
|
location = location.to_sym
|
|
266
279
|
|
|
267
|
-
|
|
268
|
-
if r[0] == line and r[1] == location
|
|
269
|
-
if tracker.options[:combine_locations]
|
|
270
|
-
return true
|
|
271
|
-
elsif r[2] == result
|
|
272
|
-
return true
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
false
|
|
280
|
+
return location, line
|
|
278
281
|
end
|
|
279
282
|
|
|
280
283
|
#Checks if an expression contains string interpolation.
|
|
@@ -348,6 +351,22 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
348
351
|
when :or
|
|
349
352
|
has_immediate_user_input? exp.lhs or
|
|
350
353
|
has_immediate_user_input? exp.rhs
|
|
354
|
+
when :splat, :kwsplat
|
|
355
|
+
exp.each_sexp do |e|
|
|
356
|
+
match = has_immediate_user_input?(e)
|
|
357
|
+
return match if match
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
false
|
|
361
|
+
when :hash
|
|
362
|
+
if kwsplat? exp
|
|
363
|
+
exp[1].each_sexp do |e|
|
|
364
|
+
match = has_immediate_user_input?(e)
|
|
365
|
+
return match if match
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
false
|
|
369
|
+
end
|
|
351
370
|
else
|
|
352
371
|
false
|
|
353
372
|
end
|
|
@@ -460,11 +479,11 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
460
479
|
if gem_name and info = tracker.config.get_gem(gem_name)
|
|
461
480
|
info
|
|
462
481
|
elsif @app_tree.exists?("Gemfile")
|
|
463
|
-
"Gemfile"
|
|
482
|
+
@app_tree.file_path "Gemfile"
|
|
464
483
|
elsif @app_tree.exists?("gems.rb")
|
|
465
|
-
"gems.rb"
|
|
484
|
+
@app_tree.file_path "gems.rb"
|
|
466
485
|
else
|
|
467
|
-
"config/environment.rb"
|
|
486
|
+
@app_tree.file_path "config/environment.rb"
|
|
468
487
|
end
|
|
469
488
|
end
|
|
470
489
|
|