aikido-zen 0.2.0-x86_64-linux → 1.0.1.beta.2-x86_64-linux
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/.aikido +6 -0
- data/.simplecov +6 -0
- data/README.md +67 -83
- data/benchmarks/README.md +8 -12
- data/docs/rails.md +1 -1
- data/lib/aikido/zen/agent.rb +10 -8
- data/lib/aikido/zen/api_client.rb +14 -4
- data/lib/aikido/zen/background_worker.rb +52 -0
- data/lib/aikido/zen/collector.rb +12 -1
- data/lib/aikido/zen/config.rb +20 -0
- data/lib/aikido/zen/context.rb +4 -0
- data/lib/aikido/zen/detached_agent/agent.rb +78 -0
- data/lib/aikido/zen/detached_agent/front_object.rb +37 -0
- data/lib/aikido/zen/detached_agent/server.rb +41 -0
- data/lib/aikido/zen/detached_agent.rb +2 -0
- data/lib/aikido/zen/errors.rb +8 -0
- data/lib/aikido/zen/internals.rb +41 -7
- data/lib/aikido/zen/libzen-v0.1.39-x86_64-linux.so +0 -0
- data/lib/aikido/zen/middleware/rack_throttler.rb +9 -3
- data/lib/aikido/zen/middleware/request_tracker.rb +6 -4
- data/lib/aikido/zen/outbound_connection_monitor.rb +4 -0
- data/lib/aikido/zen/rails_engine.rb +8 -8
- data/lib/aikido/zen/rate_limiter/breaker.rb +3 -3
- data/lib/aikido/zen/rate_limiter.rb +6 -11
- data/lib/aikido/zen/request/heuristic_router.rb +6 -0
- data/lib/aikido/zen/request/rails_router.rb +6 -18
- data/lib/aikido/zen/request/schema/auth_schemas.rb +14 -0
- data/lib/aikido/zen/request/schema.rb +18 -0
- data/lib/aikido/zen/runtime_settings.rb +2 -2
- data/lib/aikido/zen/scanners/path_traversal_scanner.rb +4 -2
- data/lib/aikido/zen/scanners/shell_injection_scanner.rb +4 -2
- data/lib/aikido/zen/scanners/sql_injection_scanner.rb +4 -2
- data/lib/aikido/zen/scanners/ssrf/private_ip_checker.rb +33 -21
- data/lib/aikido/zen/scanners/ssrf_scanner.rb +6 -1
- data/lib/aikido/zen/scanners/stored_ssrf_scanner.rb +6 -0
- data/lib/aikido/zen/sink.rb +11 -1
- data/lib/aikido/zen/sinks/action_controller.rb +9 -4
- data/lib/aikido/zen/sinks/async_http.rb +35 -16
- data/lib/aikido/zen/sinks/curb.rb +52 -26
- data/lib/aikido/zen/sinks/em_http.rb +39 -25
- data/lib/aikido/zen/sinks/excon.rb +63 -45
- data/lib/aikido/zen/sinks/file.rb +67 -71
- data/lib/aikido/zen/sinks/http.rb +38 -19
- data/lib/aikido/zen/sinks/httpclient.rb +51 -22
- data/lib/aikido/zen/sinks/httpx.rb +37 -18
- data/lib/aikido/zen/sinks/kernel.rb +18 -57
- data/lib/aikido/zen/sinks/mysql2.rb +19 -7
- data/lib/aikido/zen/sinks/net_http.rb +37 -19
- data/lib/aikido/zen/sinks/patron.rb +41 -24
- data/lib/aikido/zen/sinks/pg.rb +50 -27
- data/lib/aikido/zen/sinks/resolv.rb +37 -16
- data/lib/aikido/zen/sinks/socket.rb +46 -17
- data/lib/aikido/zen/sinks/sqlite3.rb +31 -12
- data/lib/aikido/zen/sinks/trilogy.rb +19 -7
- data/lib/aikido/zen/sinks.rb +29 -20
- data/lib/aikido/zen/sinks_dsl.rb +226 -0
- data/lib/aikido/zen/version.rb +2 -2
- data/lib/aikido/zen/worker.rb +5 -0
- data/lib/aikido/zen.rb +59 -9
- data/placeholder/.gitignore +4 -0
- data/placeholder/README.md +11 -0
- data/placeholder/Rakefile +75 -0
- data/placeholder/lib/placeholder.rb.template +3 -0
- data/placeholder/placeholder.gemspec.template +20 -0
- data/tasklib/bench.rake +29 -6
- data/tasklib/libzen.rake +70 -66
- data/tasklib/wrk.rb +88 -0
- metadata +23 -13
- data/CHANGELOG.md +0 -25
- data/lib/aikido/zen/libzen-v0.1.37.x86_64.so +0 -0
- data/lib/aikido.rb +0 -3
@@ -12,11 +12,11 @@ module Aikido::Zen
|
|
12
12
|
def initialize(
|
13
13
|
config: Aikido::Zen.config,
|
14
14
|
settings: Aikido::Zen.runtime_settings,
|
15
|
-
|
15
|
+
detached_agent: Aikido::Zen.detached_agent
|
16
16
|
)
|
17
17
|
@config = config
|
18
18
|
@settings = settings
|
19
|
-
@
|
19
|
+
@detached_agent = detached_agent
|
20
20
|
end
|
21
21
|
|
22
22
|
def block?(controller)
|
@@ -43,16 +43,21 @@ module Aikido::Zen
|
|
43
43
|
end
|
44
44
|
|
45
45
|
private def should_throttle?(request)
|
46
|
+
return false unless @settings.endpoints[request.route].rate_limiting.enabled?
|
46
47
|
return false if @settings.skip_protection_for_ips.include?(request.ip)
|
47
48
|
|
48
|
-
@
|
49
|
+
result = @detached_agent.calculate_rate_limits(request)
|
50
|
+
return false unless result
|
51
|
+
|
52
|
+
request.env["aikido.rate_limiting"] = result
|
53
|
+
request.env["aikido.rate_limiting"].throttled?
|
49
54
|
end
|
50
55
|
|
51
56
|
# @param request [Aikido::Zen::Request]
|
52
57
|
private def should_block_user?(request)
|
53
58
|
return false if request.actor.nil?
|
54
59
|
|
55
|
-
|
60
|
+
Aikido::Zen.runtime_settings.blocked_user_ids&.include?(request.actor.id)
|
56
61
|
end
|
57
62
|
end
|
58
63
|
|
@@ -1,26 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../
|
3
|
+
require_relative "../scanners/ssrf_scanner"
|
4
4
|
require_relative "../outbound_connection_monitor"
|
5
5
|
|
6
6
|
module Aikido::Zen
|
7
7
|
module Sinks
|
8
8
|
module Async
|
9
9
|
module HTTP
|
10
|
+
def self.load_sinks!
|
11
|
+
if Gem.loaded_specs["async-http"]
|
12
|
+
require "async/http"
|
13
|
+
|
14
|
+
::Async::HTTP::Client.prepend(Async::HTTP::ClientExtensions)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
10
18
|
SINK = Sinks.add("async-http", scanners: [
|
11
|
-
|
12
|
-
|
19
|
+
Scanners::SSRFScanner,
|
20
|
+
OutboundConnectionMonitor
|
13
21
|
])
|
14
22
|
|
15
|
-
module
|
16
|
-
def
|
23
|
+
module Helpers
|
24
|
+
def self.scan(request, connection, operation)
|
25
|
+
SINK.scan(
|
26
|
+
request: request,
|
27
|
+
connection: connection,
|
28
|
+
operation: operation
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClientExtensions
|
34
|
+
extend Sinks::DSL
|
35
|
+
|
36
|
+
sink_around :call do |super_call, request|
|
17
37
|
uri = URI(format("%<scheme>s://%<authority>s%<path>s", {
|
18
38
|
scheme: request.scheme || scheme,
|
19
39
|
authority: request.authority || authority,
|
20
40
|
path: request.path
|
21
41
|
}))
|
22
42
|
|
23
|
-
wrapped_request =
|
43
|
+
wrapped_request = Scanners::SSRFScanner::Request.new(
|
24
44
|
verb: request.method,
|
25
45
|
uri: uri,
|
26
46
|
headers: request.headers.to_h,
|
@@ -28,22 +48,21 @@ module Aikido::Zen
|
|
28
48
|
)
|
29
49
|
|
30
50
|
# Store the request information so the DNS sinks can pick it up.
|
31
|
-
|
51
|
+
context = Aikido::Zen.current_context
|
52
|
+
if context
|
32
53
|
prev_request = context["ssrf.request"]
|
33
54
|
context["ssrf.request"] = wrapped_request
|
34
55
|
end
|
35
56
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
operation: "request"
|
40
|
-
)
|
57
|
+
connection = OutboundConnection.from_uri(uri)
|
58
|
+
|
59
|
+
Helpers.scan(wrapped_request, connection, "request")
|
41
60
|
|
42
|
-
response =
|
61
|
+
response = super_call.call
|
43
62
|
|
44
|
-
|
63
|
+
Scanners::SSRFScanner.track_redirects(
|
45
64
|
request: wrapped_request,
|
46
|
-
response:
|
65
|
+
response: Scanners::SSRFScanner::Response.new(
|
47
66
|
status: response.status,
|
48
67
|
headers: response.headers.to_h,
|
49
68
|
header_normalizer: ->(value) { Array(value).join(", ") }
|
@@ -60,4 +79,4 @@ module Aikido::Zen
|
|
60
79
|
end
|
61
80
|
end
|
62
81
|
|
63
|
-
|
82
|
+
Aikido::Zen::Sinks::Async::HTTP.load_sinks!
|
@@ -1,19 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../
|
3
|
+
require_relative "../scanners/ssrf_scanner"
|
4
4
|
require_relative "../outbound_connection_monitor"
|
5
5
|
|
6
6
|
module Aikido::Zen
|
7
7
|
module Sinks
|
8
8
|
module Curl
|
9
|
+
def self.load_sinks!
|
10
|
+
if Gem.loaded_specs["curb"]
|
11
|
+
require "curb"
|
12
|
+
|
13
|
+
::Curl::Easy.prepend(Curl::EasyExtensions)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
9
17
|
SINK = Sinks.add("curb", scanners: [
|
10
|
-
|
11
|
-
|
18
|
+
Scanners::SSRFScanner,
|
19
|
+
OutboundConnectionMonitor
|
12
20
|
])
|
13
21
|
|
14
|
-
module
|
22
|
+
module Helpers
|
15
23
|
def self.wrap_request(curl, url: curl.url)
|
16
|
-
|
24
|
+
Scanners::SSRFScanner::Request.new(
|
17
25
|
verb: nil, # Curb hides this by directly setting an option in C
|
18
26
|
uri: URI(url),
|
19
27
|
headers: curl.headers
|
@@ -33,29 +41,40 @@ module Aikido::Zen
|
|
33
41
|
status = curl.status.to_i
|
34
42
|
end
|
35
43
|
|
36
|
-
|
44
|
+
Scanners::SSRFScanner::Response.new(status: status, headers: headers)
|
37
45
|
end
|
38
46
|
|
39
|
-
def
|
40
|
-
|
47
|
+
def self.scan(request, connection, operation)
|
48
|
+
SINK.scan(
|
49
|
+
request: request,
|
50
|
+
connection: connection,
|
51
|
+
operation: operation
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module EasyExtensions
|
57
|
+
extend Sinks::DSL
|
58
|
+
|
59
|
+
sink_around :perform do |super_call|
|
60
|
+
wrapped_request = Helpers.wrap_request(self)
|
41
61
|
|
42
62
|
# Store the request information so the DNS sinks can pick it up.
|
43
|
-
|
63
|
+
context = Aikido::Zen.current_context
|
64
|
+
if context
|
44
65
|
prev_request = context["ssrf.request"]
|
45
66
|
context["ssrf.request"] = wrapped_request
|
46
67
|
end
|
47
68
|
|
48
|
-
|
49
|
-
connection: Aikido::Zen::OutboundConnection.from_uri(URI(url)),
|
50
|
-
request: wrapped_request,
|
51
|
-
operation: "request"
|
52
|
-
)
|
69
|
+
connection = OutboundConnection.from_uri(URI(url))
|
53
70
|
|
54
|
-
|
71
|
+
Helpers.scan(wrapped_request, connection, "request")
|
55
72
|
|
56
|
-
|
73
|
+
response = super_call.call
|
74
|
+
|
75
|
+
Scanners::SSRFScanner.track_redirects(
|
57
76
|
request: wrapped_request,
|
58
|
-
response:
|
77
|
+
response: Helpers.wrap_response(self)
|
59
78
|
)
|
60
79
|
|
61
80
|
# When libcurl has follow_location set, it will handle redirections
|
@@ -67,14 +86,21 @@ module Aikido::Zen
|
|
67
86
|
# stop the response from being exposed to the user. This downgrades
|
68
87
|
# the SSRF into a blind SSRF, which is better than doing nothing.
|
69
88
|
if url != last_effective_url
|
70
|
-
last_effective_request =
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
89
|
+
last_effective_request = Helpers.wrap_request(self, url: last_effective_url)
|
90
|
+
|
91
|
+
# Code coverage is disabled here because the else clause is a no-op,
|
92
|
+
# so there is nothing to cover.
|
93
|
+
# :nocov:
|
94
|
+
if context
|
95
|
+
context["ssrf.request"] = last_effective_request
|
96
|
+
else
|
97
|
+
# empty
|
98
|
+
end
|
99
|
+
# :nocov:
|
100
|
+
|
101
|
+
connection = OutboundConnection.from_uri(URI(last_effective_url))
|
102
|
+
|
103
|
+
Helpers.scan(last_effective_request, connection, "request")
|
78
104
|
end
|
79
105
|
|
80
106
|
response
|
@@ -86,4 +112,4 @@ module Aikido::Zen
|
|
86
112
|
end
|
87
113
|
end
|
88
114
|
|
89
|
-
|
115
|
+
Aikido::Zen::Sinks::Curl.load_sinks!
|
@@ -1,20 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../
|
3
|
+
require_relative "../scanners/ssrf_scanner"
|
4
4
|
require_relative "../outbound_connection_monitor"
|
5
5
|
|
6
6
|
module Aikido::Zen
|
7
7
|
module Sinks
|
8
8
|
module EventMachine
|
9
9
|
module HttpRequest
|
10
|
+
def self.load_sinks!
|
11
|
+
if Gem.loaded_specs["em-http-request"]
|
12
|
+
require "em-http-request"
|
13
|
+
|
14
|
+
::EventMachine::HttpRequest.use(EventMachine::HttpRequest::Middleware)
|
15
|
+
|
16
|
+
# NOTE: We can't use middleware to intercept requests as we want to ensure any
|
17
|
+
# modifications to the request from user-supplied middleware are already applied
|
18
|
+
# before we scan the request.
|
19
|
+
::EventMachine::HttpClient.prepend(EventMachine::HttpRequest::HttpClientExtensions)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
10
23
|
SINK = Sinks.add("em-http-request", scanners: [
|
11
|
-
|
12
|
-
|
24
|
+
Scanners::SSRFScanner,
|
25
|
+
OutboundConnectionMonitor
|
13
26
|
])
|
14
27
|
|
15
|
-
module
|
16
|
-
def
|
17
|
-
|
28
|
+
module Helpers
|
29
|
+
def self.scan(request, connection, operation)
|
30
|
+
SINK.scan(
|
31
|
+
request: request,
|
32
|
+
connection: connection,
|
33
|
+
operation: operation
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module HttpClientExtensions
|
39
|
+
extend Sinks::DSL
|
40
|
+
|
41
|
+
sink_before :send_request do
|
42
|
+
wrapped_request = Scanners::SSRFScanner::Request.new(
|
18
43
|
verb: req.method.to_s,
|
19
44
|
uri: URI(req.uri),
|
20
45
|
headers: req.headers
|
@@ -24,16 +49,12 @@ module Aikido::Zen
|
|
24
49
|
context = Aikido::Zen.current_context
|
25
50
|
context["ssrf.request"] = wrapped_request if context
|
26
51
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
port: req.port
|
31
|
-
),
|
32
|
-
request: wrapped_request,
|
33
|
-
operation: "request"
|
52
|
+
connection = OutboundConnection.new(
|
53
|
+
host: req.host,
|
54
|
+
port: req.port
|
34
55
|
)
|
35
56
|
|
36
|
-
|
57
|
+
Helpers.scan(wrapped_request, connection, "request")
|
37
58
|
end
|
38
59
|
end
|
39
60
|
|
@@ -43,13 +64,13 @@ module Aikido::Zen
|
|
43
64
|
context = Aikido::Zen.current_context
|
44
65
|
context["ssrf.request"] = nil if context
|
45
66
|
|
46
|
-
|
47
|
-
request:
|
67
|
+
Scanners::SSRFScanner.track_redirects(
|
68
|
+
request: Scanners::SSRFScanner::Request.new(
|
48
69
|
verb: client.req.method,
|
49
70
|
uri: URI(client.req.uri),
|
50
71
|
headers: client.req.headers
|
51
72
|
),
|
52
|
-
response:
|
73
|
+
response: Scanners::SSRFScanner::Response.new(
|
53
74
|
status: client.response_header.status,
|
54
75
|
headers: client.response_header.to_h
|
55
76
|
)
|
@@ -61,11 +82,4 @@ module Aikido::Zen
|
|
61
82
|
end
|
62
83
|
end
|
63
84
|
|
64
|
-
::EventMachine::HttpRequest
|
65
|
-
.use(Aikido::Zen::Sinks::EventMachine::HttpRequest::Middleware)
|
66
|
-
|
67
|
-
# NOTE: We can't use middleware to intercept requests as we want to ensure any
|
68
|
-
# modifications to the request from user-supplied middleware are already applied
|
69
|
-
# before we scan the request.
|
70
|
-
::EventMachine::HttpClient
|
71
|
-
.prepend(Aikido::Zen::Sinks::EventMachine::HttpRequest::Extensions)
|
85
|
+
Aikido::Zen::Sinks::EventMachine::HttpRequest.load_sinks!
|
@@ -1,31 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../
|
3
|
+
require_relative "../scanners/ssrf_scanner"
|
4
4
|
require_relative "../outbound_connection_monitor"
|
5
5
|
|
6
6
|
module Aikido::Zen
|
7
7
|
module Sinks
|
8
8
|
module Excon
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
])
|
9
|
+
def self.load_sinks!
|
10
|
+
if Gem.loaded_specs["excon"]
|
11
|
+
require "excon"
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
#
|
17
|
-
# @param connection [Hash<Symbol, Object>] the data set in the connection.
|
18
|
-
# @param request [Hash<Symbol, Object>] the data overrides sent for each
|
19
|
-
# request.
|
20
|
-
#
|
21
|
-
# @return [Aikido::Zen::OutboundConnection]
|
22
|
-
def self.build_outbound(connection, request)
|
23
|
-
Aikido::Zen::OutboundConnection.new(
|
24
|
-
host: request.fetch(:hostname) { connection[:hostname] },
|
25
|
-
port: request.fetch(:port) { connection[:port] }
|
26
|
-
)
|
13
|
+
::Excon::Connection.prepend(ConnectionExtensions)
|
14
|
+
::Excon::Middleware::RedirectFollower.prepend(RedirectFollowerExtensions)
|
27
15
|
end
|
16
|
+
end
|
17
|
+
|
18
|
+
SINK = Sinks.add("excon", scanners: [
|
19
|
+
Scanners::SSRFScanner,
|
20
|
+
OutboundConnectionMonitor
|
21
|
+
])
|
28
22
|
|
23
|
+
module Helpers
|
29
24
|
def self.build_request(connection, request)
|
30
25
|
uri = URI(format("%<scheme>s://%<host>s:%<port>i%<path>s", {
|
31
26
|
scheme: request.fetch(:scheme) { connection[:scheme] },
|
@@ -35,45 +30,61 @@ module Aikido::Zen
|
|
35
30
|
}))
|
36
31
|
uri.query = request.fetch(:query) { connection[:query] }
|
37
32
|
|
38
|
-
|
33
|
+
Scanners::SSRFScanner::Request.new(
|
39
34
|
verb: request.fetch(:method) { connection[:method] },
|
40
35
|
uri: uri,
|
41
36
|
headers: connection[:headers].to_h.merge(request[:headers].to_h)
|
42
37
|
)
|
43
38
|
end
|
44
39
|
|
45
|
-
def request
|
46
|
-
|
40
|
+
def self.scan(request, connection, operation)
|
41
|
+
SINK.scan(
|
42
|
+
request: request,
|
43
|
+
connection: connection,
|
44
|
+
operation: operation
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module ConnectionExtensions
|
50
|
+
extend Sinks::DSL
|
51
|
+
|
52
|
+
sink_around :request do |super_call, params = {}|
|
53
|
+
request = Helpers.build_request(@data, params)
|
47
54
|
|
48
55
|
# Store the request information so the DNS sinks can pick it up.
|
49
|
-
|
56
|
+
context = Aikido::Zen.current_context
|
57
|
+
if context
|
50
58
|
prev_request = context["ssrf.request"]
|
51
59
|
context["ssrf.request"] = request
|
52
60
|
end
|
53
61
|
|
54
|
-
|
55
|
-
connection: Aikido::Zen::OutboundConnection.from_uri(request.uri),
|
56
|
-
request: request,
|
57
|
-
operation: "request"
|
58
|
-
)
|
62
|
+
connection = OutboundConnection.from_uri(request.uri)
|
59
63
|
|
60
|
-
|
64
|
+
Helpers.scan(request, connection, "request")
|
61
65
|
|
62
|
-
|
66
|
+
response = super_call.call
|
67
|
+
|
68
|
+
Scanners::SSRFScanner.track_redirects(
|
63
69
|
request: request,
|
64
|
-
response:
|
70
|
+
response: Scanners::SSRFScanner::Response.new(
|
65
71
|
status: response.status,
|
66
72
|
headers: response.headers.to_h
|
67
73
|
)
|
68
74
|
)
|
69
75
|
|
70
76
|
response
|
71
|
-
rescue ::
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
+
rescue Sinks::DSL::PresafeError => err
|
78
|
+
outer_cause = err.cause
|
79
|
+
case outer_cause
|
80
|
+
when ::Excon::Error::Socket
|
81
|
+
inner_cause = outer_cause.cause
|
82
|
+
# Excon wraps errors inside the lower level layer. This only happens
|
83
|
+
# to our scanning exceptions when a request is using RedirectFollower,
|
84
|
+
# so we unwrap them when it happens so host apps can handle errors
|
85
|
+
# consistently.
|
86
|
+
raise inner_cause if inner_cause.is_a?(Aikido::Zen::UnderAttackError)
|
87
|
+
end
|
77
88
|
raise
|
78
89
|
ensure
|
79
90
|
context["ssrf.request"] = prev_request if context
|
@@ -81,23 +92,30 @@ module Aikido::Zen
|
|
81
92
|
end
|
82
93
|
|
83
94
|
module RedirectFollowerExtensions
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
95
|
+
extend Sinks::DSL
|
96
|
+
|
97
|
+
sink_before :response_call do |datum|
|
98
|
+
response = datum[:response]
|
99
|
+
|
100
|
+
# Code coverage is disabled here because the else clause is a no-op,
|
101
|
+
# so there is nothing to cover.
|
102
|
+
# :nocov:
|
103
|
+
if !response.nil?
|
104
|
+
Scanners::SSRFScanner.track_redirects(
|
105
|
+
request: Helpers.build_request(datum, {}),
|
106
|
+
response: Scanners::SSRFScanner::Response.new(
|
89
107
|
status: response[:status],
|
90
108
|
headers: response[:headers]
|
91
109
|
)
|
92
110
|
)
|
111
|
+
else
|
112
|
+
# empty
|
93
113
|
end
|
94
|
-
|
95
|
-
super
|
114
|
+
# :nocov:
|
96
115
|
end
|
97
116
|
end
|
98
117
|
end
|
99
118
|
end
|
100
119
|
end
|
101
120
|
|
102
|
-
|
103
|
-
::Excon::Middleware::RedirectFollower.prepend(Aikido::Zen::Sinks::Excon::RedirectFollowerExtensions)
|
121
|
+
Aikido::Zen::Sinks::Excon.load_sinks!
|