brakeman-min 0.3.2 → 0.4.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.
- data/bin/brakeman +4 -0
- data/lib/checks/check_cross_site_scripting.rb +14 -2
- data/lib/processor.rb +2 -0
- data/lib/processors/erubis_template_processor.rb +26 -3
- data/lib/processors/output_processor.rb +17 -0
- data/lib/scanner.rb +11 -2
- data/lib/scanner_erubis.rb +29 -9
- data/lib/version.rb +1 -1
- metadata +4 -4
data/bin/brakeman
CHANGED
@@ -34,6 +34,10 @@ OptionParser.new do |opts|
|
|
34
34
|
options[:ignore_model_output] = true
|
35
35
|
end
|
36
36
|
|
37
|
+
opts.on "-e", "--escape-html", "Escape HTML by default" do
|
38
|
+
options[:escape_html] = true
|
39
|
+
end
|
40
|
+
|
37
41
|
opts.on "-r", "--report-direct", "Only report direct use of untrusted data" do |option|
|
38
42
|
options[:check_arguments] = !option
|
39
43
|
end
|
@@ -30,6 +30,8 @@ class CheckCrossSiteScripting < BaseCheck
|
|
30
30
|
|
31
31
|
HAML_HELPERS = Sexp.new(:colon2, Sexp.new(:const, :Haml), :Helpers)
|
32
32
|
|
33
|
+
XML_HELPER = Sexp.new(:colon2, Sexp.new(:const, :Erubis), :XmlHelper)
|
34
|
+
|
33
35
|
URI = Sexp.new(:const, :URI)
|
34
36
|
|
35
37
|
CGI = Sexp.new(:const, :CGI)
|
@@ -48,7 +50,7 @@ class CheckCrossSiteScripting < BaseCheck
|
|
48
50
|
@current_template = template
|
49
51
|
|
50
52
|
template[:outputs].each do |out|
|
51
|
-
type, match = has_immediate_user_input?(out[1])
|
53
|
+
type, match = (out[0] == :output and has_immediate_user_input?(out[1]))
|
52
54
|
if type and not duplicate? out
|
53
55
|
add_result out
|
54
56
|
case type
|
@@ -102,6 +104,16 @@ class CheckCrossSiteScripting < BaseCheck
|
|
102
104
|
process exp[1].dup
|
103
105
|
end
|
104
106
|
|
107
|
+
#Look for calls to raw()
|
108
|
+
#Otherwise, ignore
|
109
|
+
def process_escaped_output exp
|
110
|
+
if exp[1].node_type == :call and exp[1][2] == :raw
|
111
|
+
process_output exp
|
112
|
+
else
|
113
|
+
exp
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
105
117
|
#Check a call for user input
|
106
118
|
#
|
107
119
|
#
|
@@ -154,6 +166,7 @@ class CheckCrossSiteScripting < BaseCheck
|
|
154
166
|
(@matched == :model and IGNORE_MODEL_METHODS.include? method) or
|
155
167
|
(target == HAML_HELPERS and method == :html_escape) or
|
156
168
|
((target == URI or target == CGI) and method == :escape) or
|
169
|
+
(target == XML_HELPER and method == :escape_xml) or
|
157
170
|
(target == FORM_BUILDER and IGNORE_METHODS.include? method) or
|
158
171
|
(method.to_s[-1,1] == "?")
|
159
172
|
|
@@ -163,7 +176,6 @@ class CheckCrossSiteScripting < BaseCheck
|
|
163
176
|
|
164
177
|
@matched = :model
|
165
178
|
elsif @inspect_arguments and (ALL_PARAMETERS.include?(exp) or params? exp)
|
166
|
-
|
167
179
|
@matched = :params
|
168
180
|
elsif @inspect_arguments
|
169
181
|
process args
|
data/lib/processor.rb
CHANGED
@@ -50,6 +50,8 @@ class Processor
|
|
50
50
|
result = ErbTemplateProcessor.new(@tracker, name, called_from, file_name).process src
|
51
51
|
when :haml
|
52
52
|
result = HamlTemplateProcessor.new(@tracker, name, called_from, file_name).process src
|
53
|
+
when :erubis
|
54
|
+
result = ErubisTemplateProcessor.new(@tracker, name, called_from, file_name).process src
|
53
55
|
else
|
54
56
|
abort "Unknown template type: #{type} (#{name})"
|
55
57
|
end
|
@@ -2,6 +2,7 @@ require 'processors/template_processor'
|
|
2
2
|
|
3
3
|
#Processes ERB templates using Erubis instead of erb.
|
4
4
|
class ErubisTemplateProcessor < TemplateProcessor
|
5
|
+
|
5
6
|
|
6
7
|
#s(:call, TARGET, :method, s(:arglist))
|
7
8
|
def process_call exp
|
@@ -10,10 +11,10 @@ class ErubisTemplateProcessor < TemplateProcessor
|
|
10
11
|
target = process target
|
11
12
|
end
|
12
13
|
method = exp[2]
|
13
|
-
|
14
|
+
|
14
15
|
#_buf is the default output variable for Erubis
|
15
|
-
if target and target[1] == :_buf
|
16
|
-
if method == :<<
|
16
|
+
if target and (target[1] == :_buf or target[1] == :output_buffer)
|
17
|
+
if method == :<< or method == :safe_concat
|
17
18
|
args = exp[3][1] = process(exp[3][1])
|
18
19
|
|
19
20
|
if args.node_type == :call and args[2] == :to_s #just calling to_s on inner code
|
@@ -59,4 +60,26 @@ class ErubisTemplateProcessor < TemplateProcessor
|
|
59
60
|
block.line(exp.line)
|
60
61
|
block
|
61
62
|
end
|
63
|
+
|
64
|
+
#Look for assignments to output buffer
|
65
|
+
def process_attrasgn exp
|
66
|
+
if exp[1].node_type == :ivar and exp[1][1] == :@output_buffer
|
67
|
+
if exp[2] == :append= or exp[2] == :safe_append=
|
68
|
+
args = exp[3][1] = process(exp[3][1])
|
69
|
+
|
70
|
+
if args.node_type == :str
|
71
|
+
ignore
|
72
|
+
else
|
73
|
+
s = Sexp.new :escaped_output, args
|
74
|
+
s.line(exp.line)
|
75
|
+
@current_template[:outputs] << s
|
76
|
+
s
|
77
|
+
end
|
78
|
+
else
|
79
|
+
ignore
|
80
|
+
end
|
81
|
+
else
|
82
|
+
super
|
83
|
+
end
|
84
|
+
end
|
62
85
|
end
|
@@ -153,6 +153,23 @@ class OutputProcessor < Ruby2Ruby
|
|
153
153
|
out
|
154
154
|
end
|
155
155
|
|
156
|
+
def process_escaped_output exp
|
157
|
+
out = if exp[0].node_type == :str
|
158
|
+
""
|
159
|
+
else
|
160
|
+
res = process exp[0]
|
161
|
+
|
162
|
+
if res == ""
|
163
|
+
""
|
164
|
+
else
|
165
|
+
"[Escaped Output] #{res}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
exp.clear
|
169
|
+
out
|
170
|
+
end
|
171
|
+
|
172
|
+
|
156
173
|
def process_format exp
|
157
174
|
out = if exp[0].node_type == :str or exp[0].node_type == :ignore
|
158
175
|
""
|
data/lib/scanner.rb
CHANGED
@@ -53,7 +53,9 @@ class Scanner
|
|
53
53
|
@processor.process_config(RubyParser.new.parse(File.read("#@path/config/gems.rb")))
|
54
54
|
end
|
55
55
|
|
56
|
-
if File.exists? "#@path/vendor/plugins/rails_xss" or
|
56
|
+
if File.exists? "#@path/vendor/plugins/rails_xss" or
|
57
|
+
OPTIONS[:rails3] or OPTIONS[:escape_html] or
|
58
|
+
(File.exists? "#@path/Gemfile" and File.read("#@path/Gemfile").include? "rails_xss")
|
57
59
|
tracker.config[:escape_html] = true
|
58
60
|
warn "[Notice] Escaping HTML by default"
|
59
61
|
end
|
@@ -139,10 +141,17 @@ class Scanner
|
|
139
141
|
if type == :erb
|
140
142
|
if tracker.config[:escape_html]
|
141
143
|
initialize_erubis unless @initialized_erubis
|
142
|
-
|
144
|
+
type = :erubis
|
145
|
+
if OPTIONS[:rails3]
|
146
|
+
src = RailsXSSErubis.new(File.read(f)).src
|
147
|
+
else
|
148
|
+
src = ErubisEscape.new(File.read(f)).src
|
149
|
+
end
|
143
150
|
elsif tracker.config[:erubis]
|
144
151
|
initialize_erubis unless @initialized_erubis
|
145
152
|
src = ScannerErubis.new(File.read(f)).src
|
153
|
+
type = :erubis
|
154
|
+
src = ScannerErubis.new(File.read(f)).src
|
146
155
|
else
|
147
156
|
src = ERB.new(File.read(f), nil, "-").src
|
148
157
|
end
|
data/lib/scanner_erubis.rb
CHANGED
@@ -6,34 +6,49 @@ rescue LoadError => e
|
|
6
6
|
exit!
|
7
7
|
end
|
8
8
|
|
9
|
-
#This is from the
|
10
|
-
#except we don't care about plain text.
|
9
|
+
#This is from Rails 3 version of the Erubis handler
|
11
10
|
class RailsXSSErubis < ::Erubis::Eruby
|
12
11
|
include Erubis::NoTextEnhancer
|
13
12
|
|
14
13
|
#Initializes output buffer.
|
15
14
|
def add_preamble(src)
|
16
|
-
src << "
|
15
|
+
# src << "_buf = ActionView::SafeBuffer.new;\n"
|
17
16
|
end
|
18
17
|
|
19
18
|
#This does nothing.
|
20
19
|
def add_text(src, text)
|
21
|
-
#
|
20
|
+
# src << "@output_buffer << ('" << escape_text(text) << "'.html_safe!);"
|
22
21
|
end
|
23
22
|
|
24
|
-
|
23
|
+
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
24
|
+
|
25
25
|
def add_expr_literal(src, code)
|
26
|
-
|
26
|
+
if code =~ BLOCK_EXPR
|
27
|
+
src << '@output_buffer.append= ' << code
|
28
|
+
else
|
29
|
+
src << '@output_buffer.append= (' << code << ');'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_stmt(src, code)
|
34
|
+
if code =~ BLOCK_EXPR
|
35
|
+
src << '@output_buffer.append_if_string= ' << code
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
27
39
|
end
|
28
40
|
|
29
|
-
#Add an expression to the output buffer after escaping it.
|
30
41
|
def add_expr_escaped(src, code)
|
31
|
-
|
42
|
+
if code =~ BLOCK_EXPR
|
43
|
+
src << "@output_buffer.safe_append= " << code
|
44
|
+
else
|
45
|
+
src << "@output_buffer.safe_concat(" << code << ");"
|
46
|
+
end
|
32
47
|
end
|
33
48
|
|
34
49
|
#Add code to output buffer.
|
35
50
|
def add_postamble(src)
|
36
|
-
src << '
|
51
|
+
# src << '_buf.to_s'
|
37
52
|
end
|
38
53
|
end
|
39
54
|
|
@@ -41,3 +56,8 @@ end
|
|
41
56
|
class ScannerErubis < Erubis::Eruby
|
42
57
|
include Erubis::NoTextEnhancer
|
43
58
|
end
|
59
|
+
|
60
|
+
class ErubisEscape < ScannerErubis
|
61
|
+
include Erubis::EscapeEnhancer
|
62
|
+
end
|
63
|
+
|
data/lib/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
Version = "0.
|
1
|
+
Version = "0.4.0"
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 0.4.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Justin Collins
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-05-
|
17
|
+
date: 2011-05-18 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|