aikido-zen 0.1.0 → 0.2.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/.simplecov +20 -0
- data/CHANGELOG.md +20 -0
- data/README.md +11 -2
- data/benchmarks/rails7.1_sql_injection.js +30 -34
- data/docs/banner.svg +128 -129
- data/docs/config.md +8 -6
- data/docs/rails.md +2 -2
- data/lib/aikido/zen/agent.rb +6 -2
- data/lib/aikido/zen/api_client.rb +3 -3
- data/lib/aikido/zen/attack.rb +105 -36
- data/lib/aikido/zen/collector/routes.rb +2 -0
- data/lib/aikido/zen/collector.rb +19 -3
- data/lib/aikido/zen/config.rb +44 -20
- data/lib/aikido/zen/errors.rb +10 -1
- data/lib/aikido/zen/event.rb +4 -2
- data/lib/aikido/zen/internals.rb +4 -0
- data/lib/aikido/zen/middleware/check_allowed_addresses.rb +2 -14
- data/lib/aikido/zen/middleware/middleware.rb +11 -0
- data/lib/aikido/zen/middleware/{throttler.rb → rack_throttler.rb} +3 -11
- data/lib/aikido/zen/middleware/request_tracker.rb +190 -0
- data/lib/aikido/zen/middleware/set_context.rb +1 -4
- data/lib/aikido/zen/payload.rb +2 -0
- data/lib/aikido/zen/rails_engine.rb +8 -0
- data/lib/aikido/zen/rate_limiter.rb +1 -1
- data/lib/aikido/zen/request/schema/builder.rb +0 -2
- data/lib/aikido/zen/request/schema/definition.rb +0 -5
- data/lib/aikido/zen/request/schema.rb +0 -3
- data/lib/aikido/zen/scanners/path_traversal/helpers.rb +65 -0
- data/lib/aikido/zen/scanners/path_traversal_scanner.rb +61 -0
- data/lib/aikido/zen/scanners/shell_injection/helpers.rb +159 -0
- data/lib/aikido/zen/scanners/shell_injection_scanner.rb +62 -0
- data/lib/aikido/zen/scanners/sql_injection_scanner.rb +0 -4
- data/lib/aikido/zen/scanners/ssrf_scanner.rb +21 -12
- data/lib/aikido/zen/scanners.rb +2 -0
- data/lib/aikido/zen/sinks/action_controller.rb +26 -12
- data/lib/aikido/zen/sinks/file.rb +120 -0
- data/lib/aikido/zen/sinks/http.rb +1 -1
- data/lib/aikido/zen/sinks/kernel.rb +73 -0
- data/lib/aikido/zen/sinks/pg.rb +13 -12
- data/lib/aikido/zen/sinks/typhoeus.rb +1 -1
- data/lib/aikido/zen/sinks.rb +8 -0
- data/lib/aikido/zen/system_info.rb +1 -1
- data/lib/aikido/zen/version.rb +2 -2
- data/lib/aikido/zen.rb +14 -1
- data/tasklib/bench.rake +3 -2
- metadata +16 -7
@@ -112,7 +112,8 @@ module Aikido::Zen
|
|
112
112
|
is_port_relevant = input_uri.port != input_uri.default_port
|
113
113
|
return false if is_port_relevant && input_uri.port != conn_uri.port
|
114
114
|
|
115
|
-
conn_uri.hostname == input_uri.hostname
|
115
|
+
conn_uri.hostname == input_uri.hostname &&
|
116
|
+
conn_uri.port == input_uri.port
|
116
117
|
end
|
117
118
|
|
118
119
|
def private_ip?(hostname)
|
@@ -128,8 +129,11 @@ module Aikido::Zen
|
|
128
129
|
# * The input itself, if it already looks like a URI.
|
129
130
|
# * The input prefixed with http://
|
130
131
|
# * The input prefixed with https://
|
132
|
+
# * The input prefixed with the scheme of the request's URI, to consider
|
133
|
+
# things like an FTP request (to "ftp://localhost") with a plain host
|
134
|
+
# as a user-input ("localhost").
|
131
135
|
#
|
132
|
-
# @return [
|
136
|
+
# @return [Array<URI>] a list of unique URIs based on the above criteria.
|
133
137
|
def uris_from_input
|
134
138
|
input = @input.to_s
|
135
139
|
|
@@ -138,10 +142,12 @@ module Aikido::Zen
|
|
138
142
|
# valid hostname. We should do the same for the input.
|
139
143
|
input = format("[%s]", input) if unescaped_ipv6?(input)
|
140
144
|
|
141
|
-
[
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
+
[
|
146
|
+
input,
|
147
|
+
"http://#{input}",
|
148
|
+
"https://#{input}",
|
149
|
+
"#{@request_uri.scheme}://#{input}"
|
150
|
+
].map { |candidate| as_uri(candidate) }.compact.uniq
|
145
151
|
end
|
146
152
|
|
147
153
|
def as_uri(string)
|
@@ -222,11 +228,11 @@ module Aikido::Zen
|
|
222
228
|
# @api private
|
223
229
|
class RedirectChains
|
224
230
|
def initialize
|
225
|
-
@redirects = {}
|
231
|
+
@redirects = Hash.new { |h, k| h[k] = [] }
|
226
232
|
end
|
227
233
|
|
228
234
|
def add(source:, destination:)
|
229
|
-
@redirects[destination]
|
235
|
+
@redirects[destination].push(source)
|
230
236
|
self
|
231
237
|
end
|
232
238
|
|
@@ -236,11 +242,14 @@ module Aikido::Zen
|
|
236
242
|
#
|
237
243
|
# @param uri [URI]
|
238
244
|
# @return [URI, nil]
|
239
|
-
def origin(uri)
|
240
|
-
source = @redirects[uri]
|
245
|
+
def origin(uri, visited = Set.new)
|
246
|
+
source = @redirects[uri].first
|
241
247
|
|
242
|
-
if
|
243
|
-
|
248
|
+
return source if visited.include?(source)
|
249
|
+
visited << source
|
250
|
+
|
251
|
+
if !@redirects[source].empty?
|
252
|
+
origin(source, visited)
|
244
253
|
else
|
245
254
|
source
|
246
255
|
end
|
data/lib/aikido/zen/scanners.rb
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
module Aikido::Zen
|
4
4
|
module Sinks
|
5
5
|
module ActionController
|
6
|
-
# Implements the "middleware" for
|
7
|
-
# need to check at the end of the `before_action`
|
8
|
-
# an actual Rack middleware, to allow for calls to
|
9
|
-
# made from before_actions in the host app, thus allowing
|
10
|
-
# by user ID rather than solely by IP.
|
11
|
-
class
|
6
|
+
# Implements the "middleware" for blocking requests (i.e.: rate-limiting or blocking
|
7
|
+
# user/bots) in Rails apps, where we need to check at the end of the `before_action`
|
8
|
+
# chain, rather than in an actual Rack middleware, to allow for calls to
|
9
|
+
# `Zen.track_user` being made from before_actions in the host app, thus allowing
|
10
|
+
# block/rate-limit by user ID rather than solely by IP.
|
11
|
+
class BlockRequestChecker
|
12
12
|
def initialize(
|
13
13
|
config: Aikido::Zen.config,
|
14
14
|
settings: Aikido::Zen.runtime_settings,
|
@@ -19,10 +19,18 @@ module Aikido::Zen
|
|
19
19
|
@rate_limiter = rate_limiter
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def block?(controller)
|
23
23
|
context = controller.request.env[Aikido::Zen::ENV_KEY]
|
24
24
|
request = context.request
|
25
25
|
|
26
|
+
if should_block_user?(request)
|
27
|
+
status, headers, body = @config.blocked_responder.call(request, :user)
|
28
|
+
controller.headers.update(headers)
|
29
|
+
controller.render plain: Array(body).join, status: status
|
30
|
+
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
26
34
|
if should_throttle?(request)
|
27
35
|
status, headers, body = @config.rate_limited_responder.call(request)
|
28
36
|
controller.headers.update(headers)
|
@@ -39,10 +47,17 @@ module Aikido::Zen
|
|
39
47
|
|
40
48
|
@rate_limiter.throttle?(request)
|
41
49
|
end
|
50
|
+
|
51
|
+
# @param request [Aikido::Zen::Request]
|
52
|
+
private def should_block_user?(request)
|
53
|
+
return false if request.actor.nil?
|
54
|
+
|
55
|
+
@settings.blocked_user_ids&.include?(request.actor.id)
|
56
|
+
end
|
42
57
|
end
|
43
58
|
|
44
|
-
def self.
|
45
|
-
@
|
59
|
+
def self.block_request_checker
|
60
|
+
@block_request_checker ||= Aikido::Zen::Sinks::ActionController::BlockRequestChecker.new
|
46
61
|
end
|
47
62
|
|
48
63
|
module Extensions
|
@@ -50,10 +65,9 @@ module Aikido::Zen
|
|
50
65
|
return super unless kind == :process_action
|
51
66
|
|
52
67
|
super do
|
53
|
-
|
54
|
-
throttled = rate_limiter.throttle(self)
|
68
|
+
checker = Aikido::Zen::Sinks::ActionController.block_request_checker
|
55
69
|
|
56
|
-
yield if block_given? && !
|
70
|
+
yield if block_given? && !checker.block?(self)
|
57
71
|
end
|
58
72
|
end
|
59
73
|
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aikido::Zen
|
4
|
+
module Sinks
|
5
|
+
module File
|
6
|
+
SINK = Sinks.add("File", scanners: [
|
7
|
+
Aikido::Zen::Scanners::PathTraversalScanner
|
8
|
+
])
|
9
|
+
|
10
|
+
module Extensions
|
11
|
+
def self.scan_path(filepath, operation)
|
12
|
+
SINK.scan(
|
13
|
+
filepath: filepath,
|
14
|
+
operation: operation
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Module to extend only the initializer method of `File` (`File.new`)
|
19
|
+
module Initiliazer
|
20
|
+
def initialize(filename, *, **)
|
21
|
+
Extensions.scan_path(filename, "new")
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def open(filename, *, **)
|
27
|
+
Extensions.scan_path(filename, "open")
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def read(filename, *)
|
32
|
+
Extensions.scan_path(filename, "read")
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
def write(filename, *, **)
|
37
|
+
Extensions.scan_path(filename, "write")
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
def join(*)
|
42
|
+
joined = super
|
43
|
+
Extensions.scan_path(joined, "join")
|
44
|
+
joined
|
45
|
+
end
|
46
|
+
|
47
|
+
def chmod(mode, *paths)
|
48
|
+
paths.each { |path| Extensions.scan_path(path, "chmod") }
|
49
|
+
super
|
50
|
+
end
|
51
|
+
|
52
|
+
def chown(user, group, *paths)
|
53
|
+
paths.each { |path| Extensions.scan_path(path, "chown") }
|
54
|
+
super
|
55
|
+
end
|
56
|
+
|
57
|
+
def rename(from, to)
|
58
|
+
Extensions.scan_path(from, "rename")
|
59
|
+
Extensions.scan_path(to, "rename")
|
60
|
+
super
|
61
|
+
end
|
62
|
+
|
63
|
+
def symlink(from, to)
|
64
|
+
Extensions.scan_path(from, "symlink")
|
65
|
+
Extensions.scan_path(to, "symlink")
|
66
|
+
super
|
67
|
+
end
|
68
|
+
|
69
|
+
def truncate(file_name, *)
|
70
|
+
Extensions.scan_path(file_name, "truncate")
|
71
|
+
super
|
72
|
+
end
|
73
|
+
|
74
|
+
def unlink(*args)
|
75
|
+
args.each do |arg|
|
76
|
+
Extensions.scan_path(arg, "unlink")
|
77
|
+
end
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
def delete(*args)
|
82
|
+
args.each do |arg|
|
83
|
+
Extensions.scan_path(arg, "delete")
|
84
|
+
end
|
85
|
+
super
|
86
|
+
end
|
87
|
+
|
88
|
+
def utime(atime, mtime, *args)
|
89
|
+
args.each do |arg|
|
90
|
+
Extensions.scan_path(arg, "utime")
|
91
|
+
end
|
92
|
+
super
|
93
|
+
end
|
94
|
+
|
95
|
+
def expand_path(filename, *)
|
96
|
+
Extensions.scan_path(filename, "expand_path")
|
97
|
+
super
|
98
|
+
end
|
99
|
+
|
100
|
+
def realpath(filename, *)
|
101
|
+
Extensions.scan_path(filename, "realpath")
|
102
|
+
super
|
103
|
+
end
|
104
|
+
|
105
|
+
def realdirpath(filename, *)
|
106
|
+
Extensions.scan_path(filename, "realdirpath")
|
107
|
+
super
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Internally, Path Traversal's scanner logic uses `expand_path`, in order to avoid recursion issues we keep
|
115
|
+
# a copy of the original method, only to be used internally.
|
116
|
+
# It's important to keep this line before prepend the Extensions module, otherwise the alias will call
|
117
|
+
# the extended method.
|
118
|
+
::File.singleton_class.alias_method :expand_path__internal_for_aikido_zen, :expand_path
|
119
|
+
::File.singleton_class.prepend(Aikido::Zen::Sinks::File::Extensions)
|
120
|
+
::File.prepend Aikido::Zen::Sinks::File::Extensions::Initiliazer
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aikido::Zen
|
4
|
+
module Sinks
|
5
|
+
module Kernel
|
6
|
+
SINK = Sinks.add("Kernel", scanners: [
|
7
|
+
Aikido::Zen::Scanners::ShellInjectionScanner
|
8
|
+
])
|
9
|
+
|
10
|
+
module Extensions
|
11
|
+
# Checks if the user introduced input is trying to execute other commands
|
12
|
+
# using Shell Injection kind of attacks.
|
13
|
+
#
|
14
|
+
# @param command [String] the _full command_ that will be executed.
|
15
|
+
# @param context [Aikido::Zen::Context]
|
16
|
+
# @param sink [Aikido::Zen::Sink] the Sink that is running the scan.
|
17
|
+
# @param operation [Symbol, String] name of the method being scanned.
|
18
|
+
#
|
19
|
+
# @return [Aikido::Zen::Attacks::ShellInjectionAttack, nil] an Attack if any
|
20
|
+
# user input is detected as part of a Shell Injection Attack, or +nil+ if it's safe.
|
21
|
+
def self.scan_command(command, operation)
|
22
|
+
SINK.scan(
|
23
|
+
command: command,
|
24
|
+
operation: operation
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
# `system, spawn` functions can be invoked in several ways. For more details,
|
29
|
+
# see [the documentation](https://ruby-doc.org/3.4.1/Kernel.html#method-i-spawn)
|
30
|
+
#
|
31
|
+
# In our context, we care primarily about two common scenarios:
|
32
|
+
# - one argument (String)
|
33
|
+
# e.g.: system("ls"), system("echo something")
|
34
|
+
# - two arguments (Hash, String)
|
35
|
+
# e.g.: system({"foo" => "bar"}, "ls"), system({"foo" => "bar"}, "echo something")
|
36
|
+
#
|
37
|
+
# In all other cases, we do not protect against shell argument injections. Specifically:
|
38
|
+
#
|
39
|
+
# If a user input contains something like $(whoami) and is passed as part of the command
|
40
|
+
# arguments (e.g., user_input = "$(whoami)"):
|
41
|
+
#
|
42
|
+
# system("echo", user_input) This is safe because Ruby automatically escapes arguments
|
43
|
+
# passed to system/spawn in this form.
|
44
|
+
#
|
45
|
+
# system("echo #{user_input}") This is not safe because Ruby interpolates the user_input
|
46
|
+
# into the command string, resulting in a potentially harmful
|
47
|
+
# command like `echo $(whoami)`.
|
48
|
+
def send_arg_to_scan(args, operation)
|
49
|
+
if args.size == 1 && args[0].is_a?(String)
|
50
|
+
Extensions.scan_command(args[0], operation)
|
51
|
+
end
|
52
|
+
|
53
|
+
if args.size == 2 && args[0].is_a?(Hash)
|
54
|
+
Extensions.scan_command(args[1], operation)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def system(*args, **)
|
59
|
+
send_arg_to_scan(args, "system")
|
60
|
+
super
|
61
|
+
end
|
62
|
+
|
63
|
+
def spawn(*args, **)
|
64
|
+
send_arg_to_scan(args, "spawn")
|
65
|
+
super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
::Kernel.singleton_class.prepend Aikido::Zen::Sinks::Kernel::Extensions
|
73
|
+
::Kernel.prepend Aikido::Zen::Sinks::Kernel::Extensions
|
data/lib/aikido/zen/sinks/pg.rb
CHANGED
@@ -7,6 +7,17 @@ module Aikido::Zen
|
|
7
7
|
module PG
|
8
8
|
SINK = Sinks.add("pg", scanners: [Scanners::SQLInjectionScanner])
|
9
9
|
|
10
|
+
# For some reason, the ActiveRecord pg adapter does not wrap exceptions in
|
11
|
+
# StatementInvalid, which leads to inconsistent handling. This guarantees
|
12
|
+
# that all Zen errors are wrapped in a StatementInvalid, so documentation
|
13
|
+
# can be consistent.
|
14
|
+
WRAP_EXCEPTIONS = if defined?(ActiveRecord::StatementInvalid)
|
15
|
+
<<~RUBY
|
16
|
+
rescue Aikido::Zen::SQLInjectionError
|
17
|
+
raise ActiveRecord::StatementInvalid
|
18
|
+
RUBY
|
19
|
+
end
|
20
|
+
|
10
21
|
module Extensions
|
11
22
|
%i[
|
12
23
|
send_query exec sync_exec async_exec
|
@@ -16,12 +27,7 @@ module Aikido::Zen
|
|
16
27
|
def #{method}(query, *)
|
17
28
|
SINK.scan(query: query, dialect: :postgresql, operation: :#{method})
|
18
29
|
super
|
19
|
-
|
20
|
-
# The pg adapter does not wrap exceptions in StatementInvalid, which
|
21
|
-
# leads to inconsistent handling. This guarantees that all Aikido
|
22
|
-
# errors are wrapped in a StatementInvalid, so documentation can be
|
23
|
-
# consistent.
|
24
|
-
raise ActiveRecord::StatementInvalid
|
30
|
+
#{WRAP_EXCEPTIONS}
|
25
31
|
end
|
26
32
|
RUBY
|
27
33
|
end
|
@@ -33,12 +39,7 @@ module Aikido::Zen
|
|
33
39
|
def #{method}(_, query, *)
|
34
40
|
SINK.scan(query: query, dialect: :postgresql, operation: :#{method})
|
35
41
|
super
|
36
|
-
|
37
|
-
# The pg adapter does not wrap exceptions in StatementInvalid, which
|
38
|
-
# leads to inconsistent handling. This guarantees that all Aikido
|
39
|
-
# errors are wrapped in a StatementInvalid, so documentation can be
|
40
|
-
# consistent.
|
41
|
-
raise ActiveRecord::StatementInvalid
|
42
|
+
#{WRAP_EXCEPTIONS}
|
42
43
|
end
|
43
44
|
RUBY
|
44
45
|
end
|
data/lib/aikido/zen/sinks.rb
CHANGED
@@ -5,6 +5,14 @@ require_relative "sink"
|
|
5
5
|
require_relative "sinks/socket"
|
6
6
|
|
7
7
|
require_relative "sinks/action_controller" if defined?(::ActionController)
|
8
|
+
require_relative "sinks/file" if defined?(::File)
|
9
|
+
|
10
|
+
# Sadly, in ruby versions lower than 3.0, it's not possible to patch the
|
11
|
+
# Kernel module because how the `prepend` method is applied
|
12
|
+
# (https://stackoverflow.com/questions/78110397/prepend-kernel-module-function-globally#comment137713906_78112924)
|
13
|
+
if RUBY_VERSION >= "3.0"
|
14
|
+
require_relative "sinks/kernel" if defined?(::Kernel)
|
15
|
+
end
|
8
16
|
require_relative "sinks/resolv" if defined?(::Resolv)
|
9
17
|
require_relative "sinks/net_http" if defined?(::Net::HTTP)
|
10
18
|
require_relative "sinks/http" if defined?(::HTTP)
|
data/lib/aikido/zen/version.rb
CHANGED
data/lib/aikido/zen.rb
CHANGED
@@ -10,13 +10,15 @@ require_relative "zen/worker"
|
|
10
10
|
require_relative "zen/agent"
|
11
11
|
require_relative "zen/api_client"
|
12
12
|
require_relative "zen/context"
|
13
|
+
require_relative "zen/middleware/check_allowed_addresses"
|
14
|
+
require_relative "zen/middleware/middleware"
|
15
|
+
require_relative "zen/middleware/request_tracker"
|
13
16
|
require_relative "zen/middleware/set_context"
|
14
17
|
require_relative "zen/outbound_connection"
|
15
18
|
require_relative "zen/outbound_connection_monitor"
|
16
19
|
require_relative "zen/runtime_settings"
|
17
20
|
require_relative "zen/rate_limiter"
|
18
21
|
require_relative "zen/scanners"
|
19
|
-
require_relative "zen/middleware/check_allowed_addresses"
|
20
22
|
require_relative "zen/rails_engine" if defined?(::Rails)
|
21
23
|
|
22
24
|
module Aikido
|
@@ -70,6 +72,11 @@ module Aikido
|
|
70
72
|
collector.track_request(request)
|
71
73
|
end
|
72
74
|
|
75
|
+
def self.track_discovered_route(request)
|
76
|
+
autostart
|
77
|
+
collector.track_route(request)
|
78
|
+
end
|
79
|
+
|
73
80
|
# Tracks a network connection made to an external service.
|
74
81
|
#
|
75
82
|
# @param connection [Aikido::Zen::OutboundConnection]
|
@@ -113,6 +120,12 @@ module Aikido
|
|
113
120
|
end
|
114
121
|
end
|
115
122
|
|
123
|
+
# Marks that the Zen middleware was installed properly
|
124
|
+
# @return void
|
125
|
+
def self.middleware_installed!
|
126
|
+
collector.middleware_installed!
|
127
|
+
end
|
128
|
+
|
116
129
|
# Load all sinks matching libraries loaded into memory. This method should
|
117
130
|
# be called after all other dependencies have been loaded into memory (i.e.
|
118
131
|
# at the end of the initialization process).
|
data/tasklib/bench.rake
CHANGED
@@ -12,11 +12,12 @@ end
|
|
12
12
|
|
13
13
|
def boot_server(dir, port:, env: {})
|
14
14
|
env["PORT"] = port.to_s
|
15
|
+
env["SECRET_KEY_BASE"] = rand(36**64).to_s(36)
|
15
16
|
|
16
17
|
Dir.chdir(dir) do
|
17
18
|
SERVER_PIDS[port] = Process.spawn(
|
18
19
|
env,
|
19
|
-
"rails", "server", "--pid", "#{Dir.pwd}/tmp/pids/server.#{port}.pid",
|
20
|
+
"rails", "server", "--pid", "#{Dir.pwd}/tmp/pids/server.#{port}.pid", "-e", "production",
|
20
21
|
out: "/dev/null"
|
21
22
|
)
|
22
23
|
rescue
|
@@ -61,7 +62,7 @@ Pathname.glob("sample_apps/*").select(&:directory?).each do |dir|
|
|
61
62
|
end
|
62
63
|
|
63
64
|
task :boot_unprotected_app do
|
64
|
-
boot_server(dir, port: 3002, env: {"
|
65
|
+
boot_server(dir, port: 3002, env: {"AIKIDO_DISABLED" => "true"})
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aikido-zen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolas Sanguinetti
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -52,7 +52,7 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
description:
|
55
|
+
description:
|
56
56
|
email:
|
57
57
|
- foca@foca.io
|
58
58
|
executables: []
|
@@ -60,6 +60,7 @@ extensions: []
|
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
62
|
- ".ruby-version"
|
63
|
+
- ".simplecov"
|
63
64
|
- ".standard.yml"
|
64
65
|
- CHANGELOG.md
|
65
66
|
- LICENSE
|
@@ -93,8 +94,10 @@ files:
|
|
93
94
|
- lib/aikido/zen/event.rb
|
94
95
|
- lib/aikido/zen/internals.rb
|
95
96
|
- lib/aikido/zen/middleware/check_allowed_addresses.rb
|
97
|
+
- lib/aikido/zen/middleware/middleware.rb
|
98
|
+
- lib/aikido/zen/middleware/rack_throttler.rb
|
99
|
+
- lib/aikido/zen/middleware/request_tracker.rb
|
96
100
|
- lib/aikido/zen/middleware/set_context.rb
|
97
|
-
- lib/aikido/zen/middleware/throttler.rb
|
98
101
|
- lib/aikido/zen/outbound_connection.rb
|
99
102
|
- lib/aikido/zen/outbound_connection_monitor.rb
|
100
103
|
- lib/aikido/zen/package.rb
|
@@ -121,6 +124,10 @@ files:
|
|
121
124
|
- lib/aikido/zen/runtime_settings/rate_limit_settings.rb
|
122
125
|
- lib/aikido/zen/scan.rb
|
123
126
|
- lib/aikido/zen/scanners.rb
|
127
|
+
- lib/aikido/zen/scanners/path_traversal/helpers.rb
|
128
|
+
- lib/aikido/zen/scanners/path_traversal_scanner.rb
|
129
|
+
- lib/aikido/zen/scanners/shell_injection/helpers.rb
|
130
|
+
- lib/aikido/zen/scanners/shell_injection_scanner.rb
|
124
131
|
- lib/aikido/zen/scanners/sql_injection_scanner.rb
|
125
132
|
- lib/aikido/zen/scanners/ssrf/dns_lookups.rb
|
126
133
|
- lib/aikido/zen/scanners/ssrf/private_ip_checker.rb
|
@@ -133,9 +140,11 @@ files:
|
|
133
140
|
- lib/aikido/zen/sinks/curb.rb
|
134
141
|
- lib/aikido/zen/sinks/em_http.rb
|
135
142
|
- lib/aikido/zen/sinks/excon.rb
|
143
|
+
- lib/aikido/zen/sinks/file.rb
|
136
144
|
- lib/aikido/zen/sinks/http.rb
|
137
145
|
- lib/aikido/zen/sinks/httpclient.rb
|
138
146
|
- lib/aikido/zen/sinks/httpx.rb
|
147
|
+
- lib/aikido/zen/sinks/kernel.rb
|
139
148
|
- lib/aikido/zen/sinks/mysql2.rb
|
140
149
|
- lib/aikido/zen/sinks/net_http.rb
|
141
150
|
- lib/aikido/zen/sinks/patron.rb
|
@@ -158,7 +167,7 @@ metadata:
|
|
158
167
|
homepage_uri: https://aikido.dev
|
159
168
|
source_code_uri: https://github.com/aikidosec/firewall-ruby
|
160
169
|
changelog_uri: https://github.com/aikidosec/firewall-ruby/blob/main/CHANGELOG.md
|
161
|
-
post_install_message:
|
170
|
+
post_install_message:
|
162
171
|
rdoc_options: []
|
163
172
|
require_paths:
|
164
173
|
- lib
|
@@ -174,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
174
183
|
version: '0'
|
175
184
|
requirements: []
|
176
185
|
rubygems_version: 3.5.22
|
177
|
-
signing_key:
|
186
|
+
signing_key:
|
178
187
|
specification_version: 4
|
179
188
|
summary: Embedded Web Application Firewall that autonomously protects Ruby apps against
|
180
189
|
common and critical attacks.
|