brakeman-min 7.0.2 → 7.1.1
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 +24 -0
- data/README.md +1 -1
- data/lib/brakeman/app_tree.rb +56 -9
- data/lib/brakeman/checks/base_check.rb +5 -2
- data/lib/brakeman/checks/check_eol_rails.rb +1 -0
- data/lib/brakeman/checks/check_eol_ruby.rb +1 -0
- data/lib/brakeman/checks/check_render.rb +5 -0
- data/lib/brakeman/checks/check_sql.rb +9 -2
- data/lib/brakeman/commandline.rb +5 -0
- data/lib/brakeman/file_path.rb +4 -0
- data/lib/brakeman/messages.rb +1 -1
- data/lib/brakeman/options.rb +4 -0
- data/lib/brakeman/parsers/haml6_embedded.rb +23 -0
- data/lib/brakeman/parsers/template_parser.rb +32 -7
- data/lib/brakeman/processor.rb +2 -0
- data/lib/brakeman/processors/alias_processor.rb +9 -0
- data/lib/brakeman/processors/base_processor.rb +2 -0
- data/lib/brakeman/processors/haml6_template_processor.rb +92 -0
- data/lib/brakeman/processors/haml_template_processor.rb +8 -2
- data/lib/brakeman/processors/lib/render_helper.rb +38 -1
- data/lib/brakeman/processors/template_processor.rb +1 -1
- data/lib/brakeman/report/pager.rb +1 -1
- data/lib/brakeman/report/report_html.rb +1 -1
- data/lib/brakeman/report/report_junit.rb +4 -57
- data/lib/brakeman/report/templates/header.html.erb +8 -3
- data/lib/brakeman/report/templates/ignored_warnings.html.erb +3 -3
- data/lib/brakeman/tracker.rb +6 -0
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman.rb +4 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dd61d8da658d0f4da21e1f854a04c0e9423a91797bd93ec2a754ee6cc113570f
|
|
4
|
+
data.tar.gz: 2a725267c5b8296686867da71b9c2286c4ed423c12bb43f204dd10697afbe08f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a85e7dfae5e7dad5a99043c1f785c063a9deee56ab797d70a718ef3f6f8031dbe6b9a3307124d83c016443ae34ef15485a3f594282edf8775797a90d64a5384c
|
|
7
|
+
data.tar.gz: 70fd83ef6e68861ff57a4809098548c729fcbb67e164f541a5da4a523bb2e7a0d9a3e43f730332317e13917c9432a132af5393a8e5f0368d06abb2ea32ff6b52
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
# 7.1.1 - 2025-11-03
|
|
2
|
+
|
|
3
|
+
* Fix false positive when calling `with_content` on ViewComponents (Peer Allan)
|
|
4
|
+
* Word wrap text output in pager
|
|
5
|
+
* Consider Tempfile.create.path as safe input (Ali Ismayilov)
|
|
6
|
+
* Exclude directories before searching for files
|
|
7
|
+
* Check each side of `or` SQL arguments
|
|
8
|
+
* Ignore attribute builder in Haml 6
|
|
9
|
+
* Add `FilePath#to_path` for Ruby 3.5 compatibility (S-H-GAMELINKS)
|
|
10
|
+
* Fix SQL injection check for calculate method (Rohan Sharma)
|
|
11
|
+
* Fix missing `td` in HTML report (John Hawthorn)
|
|
12
|
+
* Check for unsafe SQL when two arguments are passed to AR methods (Patrick Brinich-Langlois)
|
|
13
|
+
|
|
14
|
+
# 7.1.0 - 2025-07-18
|
|
15
|
+
|
|
16
|
+
* Add EOL dates for Rails 8.0 and Ruby 3.4
|
|
17
|
+
* Support render model shortcut
|
|
18
|
+
* Use lazy file lists for AppTree
|
|
19
|
+
* Add Haml 6.x support
|
|
20
|
+
* Improve ignored warnings layout in HTML report (Sebastien Savater)
|
|
21
|
+
* Update JUnit report for CircleCI (Philippe Bernery)
|
|
22
|
+
* Only load escape functionality from cgi library (Earlopain)
|
|
23
|
+
* Add `--ensure-no-obsolete-ignore-entries` option (viralpraxis)
|
|
24
|
+
|
|
1
25
|
# 7.0.2 - 2025-04-04
|
|
2
26
|
|
|
3
27
|
* Fix error with empty `BUNDLE_GEMFILE` env variable
|
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[](http://brakemanscanner.org/)
|
|
2
2
|
|
|
3
3
|
[](https://circleci.com/gh/presidentbeef/brakeman)
|
|
4
|
-
[](https://qlty.sh/gh/presidentbeef/projects/brakeman)
|
|
5
5
|
|
|
6
6
|
# Brakeman
|
|
7
7
|
|
data/lib/brakeman/app_tree.rb
CHANGED
|
@@ -33,6 +33,7 @@ module Brakeman
|
|
|
33
33
|
# * "path1/" - Matches any path that contains "path1" in the project directory.
|
|
34
34
|
# * "/path1/ - Matches any path that is rooted at "path1" in the project directory.
|
|
35
35
|
#
|
|
36
|
+
# TODO: This is wacky and I don't like it.
|
|
36
37
|
def self.regex_for_paths(paths)
|
|
37
38
|
path_regexes = paths.map do |f|
|
|
38
39
|
# If path ends in a file separator then we assume it is a path rather
|
|
@@ -145,6 +146,17 @@ module Brakeman
|
|
|
145
146
|
end
|
|
146
147
|
end
|
|
147
148
|
|
|
149
|
+
|
|
150
|
+
# Call this to be able to marshall the AppTree
|
|
151
|
+
def marshallable
|
|
152
|
+
@initializer_paths = @initializer_paths.to_a
|
|
153
|
+
@controller_paths = @controller_paths.to_a
|
|
154
|
+
@template_paths = @template_paths.to_a
|
|
155
|
+
@lib_files = @file_paths.to_a
|
|
156
|
+
|
|
157
|
+
self
|
|
158
|
+
end
|
|
159
|
+
|
|
148
160
|
private
|
|
149
161
|
|
|
150
162
|
def find_helper_paths
|
|
@@ -160,7 +172,7 @@ module Brakeman
|
|
|
160
172
|
end
|
|
161
173
|
|
|
162
174
|
def find_paths(directory, extensions = ".rb")
|
|
163
|
-
select_files(glob_files(directory, "*", extensions)
|
|
175
|
+
select_files(glob_files(directory, "*", extensions))
|
|
164
176
|
end
|
|
165
177
|
|
|
166
178
|
def glob_files(directory, name, extensions = ".rb")
|
|
@@ -179,10 +191,15 @@ module Brakeman
|
|
|
179
191
|
end
|
|
180
192
|
|
|
181
193
|
files = patterns.flat_map { |pattern| Dir.glob(pattern) }
|
|
182
|
-
files.uniq
|
|
194
|
+
files.uniq.lazy
|
|
183
195
|
else
|
|
184
|
-
|
|
185
|
-
|
|
196
|
+
if directory == '.'
|
|
197
|
+
pattern = File.join(top_directories_pattern, '**', "#{name}#{extensions}")
|
|
198
|
+
else
|
|
199
|
+
pattern = "#{root_search_pattern}#{directory}/**/#{name}#{extensions}"
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
Dir.glob(pattern).lazy
|
|
186
203
|
end
|
|
187
204
|
end
|
|
188
205
|
|
|
@@ -191,7 +208,8 @@ module Brakeman
|
|
|
191
208
|
paths = reject_skipped_files(paths)
|
|
192
209
|
paths = convert_to_file_paths(paths)
|
|
193
210
|
paths = reject_global_excludes(paths)
|
|
194
|
-
reject_directories(paths)
|
|
211
|
+
paths = reject_directories(paths)
|
|
212
|
+
paths
|
|
195
213
|
end
|
|
196
214
|
|
|
197
215
|
def reject_directories(paths)
|
|
@@ -245,18 +263,47 @@ module Brakeman
|
|
|
245
263
|
end
|
|
246
264
|
|
|
247
265
|
def match_path files, path
|
|
266
|
+
# TODO: Converting to Pathnames and Strings seems like a lot
|
|
267
|
+
# of converting that could perhaps all be handled in Brakeman::FilePath
|
|
268
|
+
# instead?
|
|
248
269
|
absolute_path = Pathname.new(path)
|
|
270
|
+
|
|
249
271
|
# relative root never has a leading separator. But, we use a leading
|
|
250
272
|
# separator in a @skip_files entry to imply that a directory is
|
|
251
273
|
# "absolute" with respect to the project directory.
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
274
|
+
#
|
|
275
|
+
# Also directories need a trailing separator.
|
|
276
|
+
project_relative_path = if File.directory?(path)
|
|
277
|
+
File.join(
|
|
278
|
+
File::SEPARATOR,
|
|
279
|
+
absolute_path.relative_path_from(@project_root_path).to_s,
|
|
280
|
+
File::SEPARATOR
|
|
281
|
+
)
|
|
282
|
+
else
|
|
283
|
+
File.join(
|
|
284
|
+
File::SEPARATOR,
|
|
285
|
+
absolute_path.relative_path_from(@project_root_path).to_s
|
|
286
|
+
)
|
|
287
|
+
end
|
|
256
288
|
|
|
257
289
|
files.match(project_relative_path)
|
|
258
290
|
end
|
|
259
291
|
|
|
292
|
+
def top_directories_pattern
|
|
293
|
+
top_dirs = convert_to_file_paths(Dir.glob(File.join(root_search_pattern, '*/')))
|
|
294
|
+
top_dirs.reject! { |d| File.symlink?(d) or !File.directory?(d) }
|
|
295
|
+
top_dirs = reject_global_excludes(top_dirs)
|
|
296
|
+
top_dirs = reject_skipped_files(top_dirs)
|
|
297
|
+
|
|
298
|
+
if top_dirs.empty?
|
|
299
|
+
# Fall back to searching everything, otherwise the empty pattern
|
|
300
|
+
# will start searching from the global root
|
|
301
|
+
root_search_pattern
|
|
302
|
+
else
|
|
303
|
+
"{#{top_dirs.join(',')}}"
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
260
307
|
def root_search_pattern
|
|
261
308
|
return @root_search_pattern if @root_search_pattern
|
|
262
309
|
@root_search_pattern = search_pattern(@root)
|
|
@@ -151,10 +151,13 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
151
151
|
method[-1] == "?"
|
|
152
152
|
end
|
|
153
153
|
|
|
154
|
-
TEMP_FILE_PATH =
|
|
154
|
+
TEMP_FILE_PATH = [
|
|
155
|
+
s(:call, s(:call, s(:const, :Tempfile), :new), :path).freeze,
|
|
156
|
+
s(:call, s(:call, s(:const, :Tempfile), :create), :path).freeze
|
|
157
|
+
].freeze
|
|
155
158
|
|
|
156
159
|
def temp_file_path? exp
|
|
157
|
-
exp
|
|
160
|
+
TEMP_FILE_PATH.include? exp
|
|
158
161
|
end
|
|
159
162
|
|
|
160
163
|
#Report a warning
|
|
@@ -101,6 +101,11 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
|
|
|
101
101
|
def renderable? exp
|
|
102
102
|
return false unless call?(exp) and constant?(exp.target)
|
|
103
103
|
|
|
104
|
+
if exp.method == :with_content
|
|
105
|
+
exp = exp.target
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
return false unless constant?(exp.target)
|
|
104
109
|
target_class_name = class_name(exp.target)
|
|
105
110
|
known_renderable_class?(target_class_name) or tracker.find_method(:render_in, target_class_name)
|
|
106
111
|
end
|
|
@@ -188,11 +188,15 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
188
188
|
when :find_by_sql, :count_by_sql
|
|
189
189
|
check_by_sql_arguments call.first_arg
|
|
190
190
|
when :calculate
|
|
191
|
-
|
|
191
|
+
if call.arglist.length > 2
|
|
192
|
+
unsafe_sql?(call.second_arg) or check_find_arguments(call.third_arg)
|
|
193
|
+
elsif call.arglist.length > 1
|
|
194
|
+
unsafe_sql?(call.second_arg)
|
|
195
|
+
end
|
|
192
196
|
when :last, :first, :all
|
|
193
197
|
check_find_arguments call.first_arg
|
|
194
198
|
when :average, :count, :maximum, :minimum, :sum
|
|
195
|
-
if call.length >
|
|
199
|
+
if call.arglist.length > 1
|
|
196
200
|
unsafe_sql?(call.first_arg) or check_find_arguments(call.last_arg)
|
|
197
201
|
else
|
|
198
202
|
check_find_arguments call.last_arg
|
|
@@ -315,6 +319,9 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
315
319
|
check_hash_keys arg
|
|
316
320
|
elsif node_type? arg, :lit, :str
|
|
317
321
|
nil
|
|
322
|
+
elsif node_type? arg, :or
|
|
323
|
+
check_query_arguments(arg.lhs) or
|
|
324
|
+
check_query_arguments(arg.rhs)
|
|
318
325
|
else
|
|
319
326
|
#Hashes are safe...but we check above for hash, so...?
|
|
320
327
|
unsafe_sql? arg, :ignore_hash
|
data/lib/brakeman/commandline.rb
CHANGED
|
@@ -145,6 +145,11 @@ module Brakeman
|
|
|
145
145
|
quit Brakeman::Errors_Found_Exit_Code
|
|
146
146
|
end
|
|
147
147
|
|
|
148
|
+
if tracker.options[:ensure_no_obsolete_ignore_entries] && tracker.unused_fingerprints.any?
|
|
149
|
+
warn '[Error] Obsolete ignore entries were found, exiting with an error code.'
|
|
150
|
+
quit Brakeman::Obsolete_Ignore_Entries_Exit_Code
|
|
151
|
+
end
|
|
152
|
+
|
|
148
153
|
if ensure_ignore_notes_failed
|
|
149
154
|
quit Brakeman::Empty_Ignore_Note_Exit_Code
|
|
150
155
|
end
|
data/lib/brakeman/file_path.rb
CHANGED
|
@@ -68,6 +68,10 @@ module Brakeman
|
|
|
68
68
|
self.absolute
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
+
# Required for Pathname compatibility.
|
|
72
|
+
# Ruby 3.5+ requires Pathname#initialize to receive a String or an object with to_path method.
|
|
73
|
+
alias to_path to_str
|
|
74
|
+
|
|
71
75
|
# Returns a string with the absolute path.
|
|
72
76
|
def to_s
|
|
73
77
|
self.to_str
|
data/lib/brakeman/messages.rb
CHANGED
data/lib/brakeman/options.rb
CHANGED
|
@@ -71,6 +71,10 @@ module Brakeman::Options
|
|
|
71
71
|
options[:ensure_ignore_notes] = true
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
+
opts.on "--ensure-no-obsolete-ignore-entries", "Fail when an obsolete ignore entry is found" do
|
|
75
|
+
options[:ensure_no_obsolete_ignore_entries] = true
|
|
76
|
+
end
|
|
77
|
+
|
|
74
78
|
opts.on "-3", "--rails3", "Force Rails 3 mode" do
|
|
75
79
|
options[:rails3] = true
|
|
76
80
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[:Coffee, :CoffeeScript, :Markdown, :Sass].each do |name|
|
|
2
|
+
klass = Module.const_get("Haml::Filters::#{name}")
|
|
3
|
+
|
|
4
|
+
klass.define_method(:compile) do |node|
|
|
5
|
+
temple = [:multi]
|
|
6
|
+
temple << [:static, "<script>\n"]
|
|
7
|
+
temple << compile_with_tilt(node)
|
|
8
|
+
temple << [:static, "</script>"]
|
|
9
|
+
temple
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
klass.define_method(:compile_with_tilt) do |node|
|
|
13
|
+
# From Haml
|
|
14
|
+
text = ::Haml::Util.unescape_interpolation(node.value[:text]).gsub(/(\\+)n/) do |s|
|
|
15
|
+
escapes = $1.size
|
|
16
|
+
next s if escapes % 2 == 0
|
|
17
|
+
"#{'\\' * (escapes - 1)}\n"
|
|
18
|
+
end
|
|
19
|
+
text.prepend("\n").sub!(/\n"\z/, '"')
|
|
20
|
+
|
|
21
|
+
[:dynamic, "BrakemanFilter.render(#{text})"]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -24,6 +24,7 @@ module Brakeman
|
|
|
24
24
|
type = :erubis if erubis?
|
|
25
25
|
parse_erb path, text
|
|
26
26
|
when :haml
|
|
27
|
+
type = :haml6 if haml6?
|
|
27
28
|
parse_haml path, text
|
|
28
29
|
when :slim
|
|
29
30
|
parse_slim path, text
|
|
@@ -74,19 +75,43 @@ module Brakeman
|
|
|
74
75
|
end
|
|
75
76
|
|
|
76
77
|
def parse_haml path, text
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
if haml6?
|
|
79
|
+
require_relative 'haml6_embedded'
|
|
80
|
+
|
|
81
|
+
Haml::Template.new(filename: path.relative,
|
|
82
|
+
:escape_html => tracker.config.escape_html?,
|
|
83
|
+
generator: Temple::Generators::RailsOutputBuffer,
|
|
84
|
+
use_html_safe: true,
|
|
85
|
+
buffer_class: 'ActionView::OutputBuffer',
|
|
86
|
+
disable_capture: true,
|
|
87
|
+
) { text }.precompiled_template
|
|
88
|
+
else
|
|
89
|
+
require_relative 'haml_embedded'
|
|
79
90
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
Haml::Engine.new(text,
|
|
92
|
+
:filename => path,
|
|
93
|
+
:escape_html => tracker.config.escape_html?,
|
|
94
|
+
:escape_filter_interpolations => tracker.config.escape_filter_interpolations?
|
|
95
|
+
).precompiled.gsub(/([^\\])\\n/, '\1')
|
|
96
|
+
end
|
|
85
97
|
rescue Haml::Error => e
|
|
86
98
|
tracker.error e, ["While compiling HAML in #{path}"] << e.backtrace
|
|
87
99
|
nil
|
|
88
100
|
end
|
|
89
101
|
|
|
102
|
+
def haml6?
|
|
103
|
+
return @haml6 unless @haml6.nil?
|
|
104
|
+
|
|
105
|
+
Brakeman.load_brakeman_dependency 'haml'
|
|
106
|
+
major_version = Haml::VERSION.split('.').first.to_i
|
|
107
|
+
|
|
108
|
+
if major_version >= 6
|
|
109
|
+
@haml6 = true
|
|
110
|
+
else
|
|
111
|
+
@haml6 = false
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
90
115
|
def parse_slim path, text
|
|
91
116
|
Brakeman.load_brakeman_dependency 'slim'
|
|
92
117
|
|
data/lib/brakeman/processor.rb
CHANGED
|
@@ -63,6 +63,8 @@ module Brakeman
|
|
|
63
63
|
result = ErbTemplateProcessor.new(@tracker, name, called_from, file_name).process src
|
|
64
64
|
when :haml
|
|
65
65
|
result = HamlTemplateProcessor.new(@tracker, name, called_from, file_name).process src
|
|
66
|
+
when :haml6
|
|
67
|
+
result = Haml6TemplateProcessor.new(@tracker, name, called_from, file_name).process src
|
|
66
68
|
when :erubis
|
|
67
69
|
result = ErubisTemplateProcessor.new(@tracker, name, called_from, file_name).process src
|
|
68
70
|
when :slim
|
|
@@ -436,6 +436,12 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
436
436
|
exp.method == :open
|
|
437
437
|
end
|
|
438
438
|
|
|
439
|
+
def temp_file_create? exp
|
|
440
|
+
call? exp and
|
|
441
|
+
exp.target == TEMP_FILE_CLASS and
|
|
442
|
+
exp.method == :create
|
|
443
|
+
end
|
|
444
|
+
|
|
439
445
|
def temp_file_new line
|
|
440
446
|
s(:call, TEMP_FILE_CLASS, :new).line(line)
|
|
441
447
|
end
|
|
@@ -465,6 +471,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
465
471
|
elsif temp_file_open? call
|
|
466
472
|
local = Sexp.new(:lvar, block_args.last)
|
|
467
473
|
env.current[local] = temp_file_new(exp.line)
|
|
474
|
+
elsif temp_file_create? call
|
|
475
|
+
local = Sexp.new(:lvar, block_args.last)
|
|
476
|
+
env.current[local] = temp_file_new(exp.line)
|
|
468
477
|
else
|
|
469
478
|
block_args.each do |e|
|
|
470
479
|
#Force block arg(s) to be local
|
|
@@ -205,6 +205,7 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
|
|
|
205
205
|
rest = process rest
|
|
206
206
|
result = Sexp.new(:render, render_type, value, rest)
|
|
207
207
|
result.line(exp.line)
|
|
208
|
+
|
|
208
209
|
result
|
|
209
210
|
end
|
|
210
211
|
|
|
@@ -240,6 +241,7 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
|
|
|
240
241
|
elsif first_arg.nil?
|
|
241
242
|
type = :default
|
|
242
243
|
elsif not hash? first_arg
|
|
244
|
+
# Maybe do partial if in view?
|
|
243
245
|
type = :action
|
|
244
246
|
value = first_arg
|
|
245
247
|
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require 'brakeman/processors/haml_template_processor'
|
|
2
|
+
|
|
3
|
+
class Brakeman::Haml6TemplateProcessor < Brakeman::HamlTemplateProcessor
|
|
4
|
+
|
|
5
|
+
OUTPUT_BUFFER = s(:ivar, :@output_buffer)
|
|
6
|
+
HAML_UTILS = s(:colon2, s(:colon3, :Haml), :Util)
|
|
7
|
+
HAML_UTILS2 = s(:colon2, s(:const, :Haml), :Util)
|
|
8
|
+
# @output_buffer = output_buffer || ActionView::OutputBuffer.new
|
|
9
|
+
AV_SAFE_BUFFER = s(:or, s(:call, nil, :output_buffer), s(:call, s(:colon2, s(:const, :ActionView), :OutputBuffer), :new))
|
|
10
|
+
EMBEDDED_FILTER = s(:const, :BrakemanFilter)
|
|
11
|
+
|
|
12
|
+
def initialize(*)
|
|
13
|
+
super
|
|
14
|
+
|
|
15
|
+
# Because of how Haml 6 handles line breaks -
|
|
16
|
+
# we have to track where _haml_compiler variables are assigned.
|
|
17
|
+
# then change the line number of where they are output to where
|
|
18
|
+
# they are assigned.
|
|
19
|
+
#
|
|
20
|
+
# Like this:
|
|
21
|
+
#
|
|
22
|
+
# ; _haml_compiler1 = (params[:x];
|
|
23
|
+
# ; ); @output_buffer.safe_concat((((::Haml::Util.escape_html_safe((_haml_compiler1))).to_s).to_s));
|
|
24
|
+
#
|
|
25
|
+
# `_haml_compiler1` is output a line after it's assigned,
|
|
26
|
+
# but the assignment matches the "real" line where it is output in the template.
|
|
27
|
+
@compiler_assigns = {}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @output_buffer.safe_concat
|
|
31
|
+
def buffer_append? exp
|
|
32
|
+
call? exp and
|
|
33
|
+
output_buffer? exp.target and
|
|
34
|
+
exp.method == :safe_concat
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def process_lasgn exp
|
|
38
|
+
if exp.lhs.match?(/_haml_compiler\d+/)
|
|
39
|
+
@compiler_assigns[exp.lhs] = exp.rhs
|
|
40
|
+
ignore
|
|
41
|
+
else
|
|
42
|
+
exp
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def process_lvar exp
|
|
47
|
+
if exp.value.match?(/_haml_compiler\d+/)
|
|
48
|
+
exp = @compiler_assigns[exp.value] || exp
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
exp
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def is_escaped? exp
|
|
55
|
+
return unless call? exp
|
|
56
|
+
|
|
57
|
+
html_escaped? exp or
|
|
58
|
+
javascript_escaped? exp
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def javascript_escaped? call
|
|
62
|
+
# TODO: Adding here to match existing behavior for HAML,
|
|
63
|
+
# but really this is not safe and needs to be revisited
|
|
64
|
+
call.method == :j or
|
|
65
|
+
call.method == :escape_javascript
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def html_escaped? call
|
|
69
|
+
(call.target == HAML_UTILS or call.target == HAML_UTILS2) and
|
|
70
|
+
(call.method == :escape_html or call.method == :escape_html_safe)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def output_buffer? exp
|
|
74
|
+
exp == OUTPUT_BUFFER or
|
|
75
|
+
exp == AV_SAFE_BUFFER
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def normalize_output arg
|
|
79
|
+
arg = super(arg)
|
|
80
|
+
|
|
81
|
+
if embedded_filter? arg
|
|
82
|
+
super(arg.first_arg)
|
|
83
|
+
else
|
|
84
|
+
arg
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Handle our "fake" embedded filters
|
|
89
|
+
def embedded_filter? arg
|
|
90
|
+
call? arg and arg.method == :render and arg.target == EMBEDDED_FILTER
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -84,6 +84,12 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
|
84
84
|
:escape_once_without_haml_xss
|
|
85
85
|
]
|
|
86
86
|
|
|
87
|
+
def is_escaped? exp
|
|
88
|
+
return unless call? exp
|
|
89
|
+
|
|
90
|
+
haml_helpers? exp.target and ESCAPE_METHODS.include? exp.method
|
|
91
|
+
end
|
|
92
|
+
|
|
87
93
|
def get_pushed_value exp, default = :output
|
|
88
94
|
return exp unless sexp? exp
|
|
89
95
|
|
|
@@ -113,7 +119,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
|
113
119
|
when :call
|
|
114
120
|
if exp.method == :to_s or exp.method == :strip
|
|
115
121
|
get_pushed_value(exp.target, default)
|
|
116
|
-
elsif
|
|
122
|
+
elsif is_escaped? exp
|
|
117
123
|
get_pushed_value(exp.first_arg, :escaped_output)
|
|
118
124
|
elsif @javascript and (exp.method == :j or exp.method == :escape_javascript) # TODO: Remove - this is not safe
|
|
119
125
|
get_pushed_value(exp.first_arg, :escaped_output)
|
|
@@ -160,7 +166,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
|
160
166
|
def haml_attribute_builder? exp
|
|
161
167
|
call? exp and
|
|
162
168
|
exp.target == ATTRIBUTE_BUILDER and
|
|
163
|
-
exp.method == :build
|
|
169
|
+
(exp.method == :build or exp.method == :build_id)
|
|
164
170
|
end
|
|
165
171
|
|
|
166
172
|
def fix_textareas? exp
|
|
@@ -9,7 +9,14 @@ module Brakeman::RenderHelper
|
|
|
9
9
|
@rendered = true
|
|
10
10
|
case exp.render_type
|
|
11
11
|
when :action, :template, :inline
|
|
12
|
-
|
|
12
|
+
action = exp[2]
|
|
13
|
+
args = exp[3]
|
|
14
|
+
|
|
15
|
+
if string? action or symbol? action
|
|
16
|
+
process_action action.value, args, exp.line
|
|
17
|
+
else
|
|
18
|
+
process_model_action action, args
|
|
19
|
+
end
|
|
13
20
|
when :default
|
|
14
21
|
begin
|
|
15
22
|
process_template template_name, exp[3], nil, exp.line
|
|
@@ -49,6 +56,36 @@ module Brakeman::RenderHelper
|
|
|
49
56
|
def process_action name, args, line
|
|
50
57
|
if name.is_a? String or name.is_a? Symbol
|
|
51
58
|
process_template template_name(name), args, nil, line
|
|
59
|
+
else
|
|
60
|
+
Brakeman.debug "Not processing render #{name.inspect}"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
SINGLE_RECORD = [:first, :find, :last, :new]
|
|
65
|
+
COLLECTION = [:all, :where]
|
|
66
|
+
|
|
67
|
+
def process_model_action action, args
|
|
68
|
+
return unless call? action
|
|
69
|
+
|
|
70
|
+
method = action.method
|
|
71
|
+
|
|
72
|
+
klass = get_class_target(action) || Brakeman::Tracker::UNKNOWN_MODEL
|
|
73
|
+
name = Sexp.new(:lit, klass.downcase)
|
|
74
|
+
|
|
75
|
+
if SINGLE_RECORD.include? method
|
|
76
|
+
# Set a local variable with name based on class of model
|
|
77
|
+
# and value of the value passed to render
|
|
78
|
+
local_key = Sexp.new(:lit, :locals)
|
|
79
|
+
locals = hash_access(args, local_key) || Sexp.new(:hash)
|
|
80
|
+
hash_insert(locals, name, action)
|
|
81
|
+
hash_insert(args, local_key, locals)
|
|
82
|
+
|
|
83
|
+
process_partial name, args, action.line
|
|
84
|
+
elsif COLLECTION.include? method
|
|
85
|
+
collection_key = Sexp.new(:lit, :collection)
|
|
86
|
+
hash_insert(args, collection_key, action)
|
|
87
|
+
|
|
88
|
+
process_partial name, args, action.line
|
|
52
89
|
end
|
|
53
90
|
end
|
|
54
91
|
|
|
@@ -56,7 +56,7 @@ class Brakeman::TemplateProcessor < Brakeman::BaseProcessor
|
|
|
56
56
|
# Pull out actual output value from template
|
|
57
57
|
def normalize_output arg
|
|
58
58
|
if call? arg and [:to_s, :html_safe!, :freeze].include? arg.method
|
|
59
|
-
arg.target
|
|
59
|
+
normalize_output(arg.target) # sometimes it's foo.to_s.to_s
|
|
60
60
|
elsif node_type? arg, :if
|
|
61
61
|
branches = [arg.then_clause, arg.else_clause].compact
|
|
62
62
|
|
|
@@ -9,50 +9,7 @@ class Brakeman::Report::JUnit < Brakeman::Report::Base
|
|
|
9
9
|
doc.add REXML::XMLDecl.new '1.0', 'UTF-8'
|
|
10
10
|
|
|
11
11
|
test_suites = REXML::Element.new 'testsuites'
|
|
12
|
-
test_suites.add_attribute 'xmlns:brakeman', 'https://brakemanscanner.org/'
|
|
13
|
-
properties = test_suites.add_element 'brakeman:properties', { 'xml:id' => 'scan_info' }
|
|
14
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'app_path', 'brakeman:value' => tracker.app_path }
|
|
15
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'rails_version', 'brakeman:value' => rails_version }
|
|
16
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'security_warnings', 'brakeman:value' => all_warnings.length }
|
|
17
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'start_time', 'brakeman:value' => tracker.start_time.iso8601 }
|
|
18
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'end_time', 'brakeman:value' => tracker.end_time.iso8601 }
|
|
19
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'duration', 'brakeman:value' => tracker.duration }
|
|
20
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'checks_performed', 'brakeman:value' => checks.checks_run.join(',') }
|
|
21
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'number_of_controllers', 'brakeman:value' => tracker.controllers.length }
|
|
22
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'number_of_models', 'brakeman:value' => tracker.models.length - 1 }
|
|
23
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'ruby_version', 'brakeman:value' => number_of_templates(@tracker) }
|
|
24
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'number_of_templates', 'brakeman:value' => RUBY_VERSION }
|
|
25
|
-
properties.add_element 'brakeman:property', { 'brakeman:name' => 'brakeman_version', 'brakeman:value' => Brakeman::Version }
|
|
26
12
|
|
|
27
|
-
errors = test_suites.add_element 'brakeman:errors'
|
|
28
|
-
tracker.errors.each { |e|
|
|
29
|
-
error = errors.add_element 'brakeman:error'
|
|
30
|
-
error.add_attribute 'brakeman:message', e[:error]
|
|
31
|
-
e[:backtrace].each { |b|
|
|
32
|
-
backtrace = error.add_element 'brakeman:backtrace'
|
|
33
|
-
backtrace.add_text b
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
obsolete = test_suites.add_element 'brakeman:obsolete'
|
|
38
|
-
tracker.unused_fingerprints.each { |fingerprint|
|
|
39
|
-
obsolete.add_element 'brakeman:warning', { 'brakeman:fingerprint' => fingerprint }
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
ignored = test_suites.add_element 'brakeman:ignored'
|
|
43
|
-
ignored_warnings.each { |w|
|
|
44
|
-
warning = ignored.add_element 'brakeman:warning'
|
|
45
|
-
warning.add_attribute 'brakeman:message', w.message
|
|
46
|
-
warning.add_attribute 'brakeman:category', w.warning_type
|
|
47
|
-
warning.add_attribute 'brakeman:file', warning_file(w)
|
|
48
|
-
warning.add_attribute 'brakeman:line', w.line
|
|
49
|
-
warning.add_attribute 'brakeman:fingerprint', w.fingerprint
|
|
50
|
-
warning.add_attribute 'brakeman:confidence', w.confidence_name
|
|
51
|
-
warning.add_attribute 'brakeman:code', w.format_code
|
|
52
|
-
warning.add_text w.to_s
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
hostname = `hostname`.strip
|
|
56
13
|
i = 0
|
|
57
14
|
all_warnings
|
|
58
15
|
.map { |warning| [warning.file, [warning]] }
|
|
@@ -66,35 +23,25 @@ class Brakeman::Report::JUnit < Brakeman::Report::Base
|
|
|
66
23
|
test_suite = test_suites.add_element 'testsuite'
|
|
67
24
|
test_suite.add_attribute 'id', i
|
|
68
25
|
test_suite.add_attribute 'package', 'brakeman'
|
|
69
|
-
test_suite.add_attribute '
|
|
26
|
+
test_suite.add_attribute 'file', file.relative
|
|
70
27
|
test_suite.add_attribute 'timestamp', tracker.start_time.strftime('%FT%T')
|
|
71
|
-
test_suite.add_attribute 'hostname', hostname == '' ? 'localhost' : hostname
|
|
72
28
|
test_suite.add_attribute 'tests', checks.checks_run.length
|
|
73
29
|
test_suite.add_attribute 'failures', warnings.length
|
|
74
30
|
test_suite.add_attribute 'errors', '0'
|
|
75
31
|
test_suite.add_attribute 'time', '0'
|
|
76
32
|
|
|
77
|
-
test_suite.add_element 'properties'
|
|
78
|
-
|
|
79
33
|
warnings.each { |warning|
|
|
80
34
|
test_case = test_suite.add_element 'testcase'
|
|
81
|
-
test_case.add_attribute 'name', '
|
|
82
|
-
test_case.add_attribute '
|
|
35
|
+
test_case.add_attribute 'name', warning.check.sub(/^Brakeman::/, '')
|
|
36
|
+
test_case.add_attribute 'file', file.relative
|
|
37
|
+
test_case.add_attribute 'line', warning.line if warning.line
|
|
83
38
|
test_case.add_attribute 'time', '0'
|
|
84
39
|
|
|
85
40
|
failure = test_case.add_element 'failure'
|
|
86
41
|
failure.add_attribute 'message', warning.message
|
|
87
42
|
failure.add_attribute 'type', warning.warning_type
|
|
88
|
-
failure.add_attribute 'brakeman:fingerprint', warning.fingerprint
|
|
89
|
-
failure.add_attribute 'brakeman:file', warning_file(warning)
|
|
90
|
-
failure.add_attribute 'brakeman:line', warning.line
|
|
91
|
-
failure.add_attribute 'brakeman:confidence', warning.confidence_name
|
|
92
|
-
failure.add_attribute 'brakeman:code', warning.format_code
|
|
93
43
|
failure.add_text warning.to_s
|
|
94
44
|
}
|
|
95
|
-
|
|
96
|
-
test_suite.add_element 'system-out'
|
|
97
|
-
test_suite.add_element 'system-err'
|
|
98
45
|
}
|
|
99
46
|
|
|
100
47
|
doc.add test_suites
|
|
@@ -9,10 +9,15 @@
|
|
|
9
9
|
function toggle(context) {
|
|
10
10
|
var elem = document.getElementById(context);
|
|
11
11
|
|
|
12
|
-
if (elem.style.display != "block")
|
|
12
|
+
if (elem.style.display != "block") {
|
|
13
13
|
elem.style.display = "block";
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
elem.querySelectorAll("table").forEach(function(table) {
|
|
16
|
+
$(table).DataTable().columns.adjust();
|
|
17
|
+
});
|
|
18
|
+
} else {
|
|
15
19
|
elem.style.display = "none";
|
|
20
|
+
}
|
|
16
21
|
|
|
17
22
|
elem.parentNode.scrollIntoView();
|
|
18
23
|
}
|
|
@@ -46,7 +51,7 @@
|
|
|
46
51
|
<tr>
|
|
47
52
|
<td><%= tracker.app_path %></td>
|
|
48
53
|
<td><%= rails_version %></td>
|
|
49
|
-
<td><%= brakeman_version
|
|
54
|
+
<td><%= brakeman_version %></td>
|
|
50
55
|
<td>
|
|
51
56
|
<%= tracker.start_time %><br><br>
|
|
52
57
|
<%= tracker.duration %> seconds
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div onClick="toggle('ignored_table');"> <h2><%= warnings.length %> Ignored Warnings (click to see them)</h2 ></div>
|
|
2
|
-
<div>
|
|
3
|
-
<table
|
|
2
|
+
<div style="display:none; width:100%" id="ignored_table">
|
|
3
|
+
<table>
|
|
4
4
|
<thead>
|
|
5
5
|
<tr>
|
|
6
6
|
<th>Confidence</th>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<th>Warning Type</th>
|
|
9
9
|
<th>CWE ID</th>
|
|
10
10
|
<th>Message</th>
|
|
11
|
-
<th>Note</th>
|
|
11
|
+
<th width="auto">Note</th>
|
|
12
12
|
</tr>
|
|
13
13
|
</thead>
|
|
14
14
|
<tbody>
|
data/lib/brakeman/tracker.rb
CHANGED
data/lib/brakeman/version.rb
CHANGED
data/lib/brakeman.rb
CHANGED
|
@@ -24,6 +24,10 @@ module Brakeman
|
|
|
24
24
|
#--ensure-ignore-notes is set
|
|
25
25
|
Empty_Ignore_Note_Exit_Code = 8
|
|
26
26
|
|
|
27
|
+
# Exit code returned when at least one obsolete ignore entry is present
|
|
28
|
+
# and `--ensure-no-obsolete-ignore-entries` is set.
|
|
29
|
+
Obsolete_Ignore_Entries_Exit_Code = 9
|
|
30
|
+
|
|
27
31
|
@debug = false
|
|
28
32
|
@quiet = false
|
|
29
33
|
@loaded_dependencies = []
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brakeman-min
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 7.
|
|
4
|
+
version: 7.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Collins
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-11-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -235,6 +235,7 @@ files:
|
|
|
235
235
|
- lib/brakeman/messages.rb
|
|
236
236
|
- lib/brakeman/options.rb
|
|
237
237
|
- lib/brakeman/parsers/erubis_patch.rb
|
|
238
|
+
- lib/brakeman/parsers/haml6_embedded.rb
|
|
238
239
|
- lib/brakeman/parsers/haml_embedded.rb
|
|
239
240
|
- lib/brakeman/parsers/rails2_erubis.rb
|
|
240
241
|
- lib/brakeman/parsers/rails2_xss_plugin_erubis.rb
|
|
@@ -250,6 +251,7 @@ files:
|
|
|
250
251
|
- lib/brakeman/processors/erb_template_processor.rb
|
|
251
252
|
- lib/brakeman/processors/erubis_template_processor.rb
|
|
252
253
|
- lib/brakeman/processors/gem_processor.rb
|
|
254
|
+
- lib/brakeman/processors/haml6_template_processor.rb
|
|
253
255
|
- lib/brakeman/processors/haml_template_processor.rb
|
|
254
256
|
- lib/brakeman/processors/lib/basic_processor.rb
|
|
255
257
|
- lib/brakeman/processors/lib/call_conversion_helper.rb
|