aikido-zen 1.0.1.beta.3-arm64-darwin → 1.0.1.beta.5-arm64-darwin
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/lib/aikido/zen/rails_engine.rb +1 -15
- data/lib/aikido/zen/sinks/async_http.rb +40 -42
- data/lib/aikido/zen/sinks/curb.rb +56 -58
- data/lib/aikido/zen/sinks/em_http.rb +27 -29
- data/lib/aikido/zen/sinks/excon.rb +62 -65
- data/lib/aikido/zen/sinks/file.rb +66 -70
- data/lib/aikido/zen/sinks/http.rb +26 -28
- data/lib/aikido/zen/sinks/httpclient.rb +27 -29
- data/lib/aikido/zen/sinks/httpx.rb +27 -29
- data/lib/aikido/zen/sinks/kernel.rb +11 -12
- data/lib/aikido/zen/sinks/mysql2.rb +10 -12
- data/lib/aikido/zen/sinks/net_http.rb +25 -27
- data/lib/aikido/zen/sinks/patron.rb +56 -58
- data/lib/aikido/zen/sinks/pg.rb +23 -25
- data/lib/aikido/zen/sinks/resolv.rb +21 -21
- data/lib/aikido/zen/sinks/socket.rb +10 -12
- data/lib/aikido/zen/sinks/sqlite3.rb +18 -21
- data/lib/aikido/zen/sinks/trilogy.rb +10 -12
- data/lib/aikido/zen/sinks.rb +1 -4
- data/lib/aikido/zen/sinks_dsl.rb +27 -15
- data/lib/aikido/zen/version.rb +1 -1
- data/lib/aikido/zen.rb +26 -15
- metadata +2 -2
data/lib/aikido/zen/sinks/pg.rb
CHANGED
@@ -3,14 +3,6 @@
|
|
3
3
|
module Aikido::Zen
|
4
4
|
module Sinks
|
5
5
|
module PG
|
6
|
-
def self.load_sinks!
|
7
|
-
if Aikido::Zen.satisfy "pg", ">= 1.0"
|
8
|
-
require "pg"
|
9
|
-
|
10
|
-
::PG::Connection.prepend(PG::ConnectionExtensions)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
6
|
SINK = Sinks.add("pg", scanners: [Scanners::SQLInjectionScanner])
|
15
7
|
|
16
8
|
module Helpers
|
@@ -43,26 +35,32 @@ module Aikido::Zen
|
|
43
35
|
end
|
44
36
|
end
|
45
37
|
|
46
|
-
|
47
|
-
|
38
|
+
def self.load_sinks!
|
39
|
+
if Aikido::Zen.satisfy "pg", ">= 1.0"
|
40
|
+
require "pg"
|
48
41
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
::PG::Connection.class_eval do
|
43
|
+
extend Sinks::DSL
|
44
|
+
|
45
|
+
%i[
|
46
|
+
send_query exec sync_exec async_exec
|
47
|
+
send_query_params exec_params sync_exec_params async_exec_params
|
48
|
+
].each do |method_name|
|
49
|
+
presafe_sink_before method_name do |query|
|
50
|
+
Helpers.safe do
|
51
|
+
Helpers.scan(query, method_name)
|
52
|
+
end
|
53
|
+
end
|
56
54
|
end
|
57
|
-
end
|
58
|
-
end
|
59
55
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
56
|
+
%i[
|
57
|
+
send_prepare prepare async_prepare sync_prepare
|
58
|
+
].each do |method_name|
|
59
|
+
presafe_sink_before method_name do |_, query|
|
60
|
+
Helpers.safe do
|
61
|
+
Helpers.scan(query, method_name)
|
62
|
+
end
|
63
|
+
end
|
66
64
|
end
|
67
65
|
end
|
68
66
|
end
|
@@ -6,13 +6,6 @@ require_relative "../scanners/ssrf_scanner"
|
|
6
6
|
module Aikido::Zen
|
7
7
|
module Sinks
|
8
8
|
module Resolv
|
9
|
-
def self.load_sinks!
|
10
|
-
# In stdlib but not always required
|
11
|
-
require "resolv"
|
12
|
-
|
13
|
-
::Resolv.prepend(ResolvExtensions)
|
14
|
-
end
|
15
|
-
|
16
9
|
SINK = Sinks.add("resolv", scanners: [
|
17
10
|
Scanners::StoredSSRFScanner,
|
18
11
|
Scanners::SSRFScanner
|
@@ -35,23 +28,30 @@ module Aikido::Zen
|
|
35
28
|
end
|
36
29
|
end
|
37
30
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# is applicable.
|
31
|
+
def self.load_sinks!
|
32
|
+
# In stdlib but not always required
|
33
|
+
require "resolv"
|
42
34
|
|
43
|
-
|
35
|
+
::Resolv.class_eval do
|
36
|
+
alias_method :each_address__internal_for_aikido_zen, :each_address
|
44
37
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
38
|
+
def each_address(*args, **kwargs, &blk)
|
39
|
+
# each_address is defined "manually" because no sink method pattern
|
40
|
+
# is applicable.
|
41
|
+
|
42
|
+
name, = args
|
43
|
+
|
44
|
+
addresses = []
|
45
|
+
each_address__internal_for_aikido_zen(*args, **kwargs) do |address|
|
46
|
+
addresses << address
|
47
|
+
blk.call(address)
|
48
|
+
end
|
49
|
+
ensure
|
50
|
+
# Ensure partial results are scanned.
|
52
51
|
|
53
|
-
|
54
|
-
|
52
|
+
Sinks::DSL.safe do
|
53
|
+
Helpers.scan(name, addresses, "lookup")
|
54
|
+
end
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -10,10 +10,6 @@ module Aikido::Zen
|
|
10
10
|
# there's no way to access the internal DNS resolution that happens in C
|
11
11
|
# when using the socket primitives.
|
12
12
|
module Socket
|
13
|
-
def self.load_sinks!
|
14
|
-
::IPSocket.singleton_class.prepend(Socket::IPSocketExtensions)
|
15
|
-
end
|
16
|
-
|
17
13
|
SINK = Sinks.add("socket", scanners: [
|
18
14
|
Scanners::StoredSSRFScanner,
|
19
15
|
Scanners::SSRFScanner
|
@@ -62,15 +58,17 @@ module Aikido::Zen
|
|
62
58
|
end
|
63
59
|
end
|
64
60
|
|
65
|
-
|
66
|
-
|
61
|
+
def self.load_sinks!
|
62
|
+
::IPSocket.singleton_class.class_eval do
|
63
|
+
extend Sinks::DSL
|
67
64
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
65
|
+
sink_after :open do |socket, remote_host|
|
66
|
+
# Code coverage is disabled here because the tests are contrived and
|
67
|
+
# intentionally do not call open.
|
68
|
+
# :nocov:
|
69
|
+
Helpers.scan(remote_host, socket, "open")
|
70
|
+
# :nocov:
|
71
|
+
end
|
74
72
|
end
|
75
73
|
end
|
76
74
|
end
|
@@ -3,15 +3,6 @@
|
|
3
3
|
module Aikido::Zen
|
4
4
|
module Sinks
|
5
5
|
module SQLite3
|
6
|
-
def self.load_sinks!
|
7
|
-
if Aikido::Zen.satisfy "sqlite3", ">= 1.0"
|
8
|
-
require "sqlite3"
|
9
|
-
|
10
|
-
::SQLite3::Database.prepend(DatabaseExtensions)
|
11
|
-
::SQLite3::Statement.prepend(StatementExtensions)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
6
|
SINK = Sinks.add("sqlite3", scanners: [Scanners::SQLInjectionScanner])
|
16
7
|
|
17
8
|
module Helpers
|
@@ -24,22 +15,28 @@ module Aikido::Zen
|
|
24
15
|
end
|
25
16
|
end
|
26
17
|
|
27
|
-
|
28
|
-
|
18
|
+
def self.load_sinks!
|
19
|
+
if Aikido::Zen.satisfy "sqlite3", ">= 1.0"
|
20
|
+
require "sqlite3"
|
29
21
|
|
30
|
-
|
22
|
+
::SQLite3::Database.class_eval do
|
23
|
+
extend Sinks::DSL
|
31
24
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
25
|
+
private
|
26
|
+
|
27
|
+
# SQLite3::Database#exec_batch is an internal native private method.
|
28
|
+
sink_before :exec_batch do |sql|
|
29
|
+
Helpers.scan(sql, "exec_batch")
|
30
|
+
end
|
31
|
+
end
|
37
32
|
|
38
|
-
|
39
|
-
|
33
|
+
::SQLite3::Statement.class_eval do
|
34
|
+
extend Sinks::DSL
|
40
35
|
|
41
|
-
|
42
|
-
|
36
|
+
sink_before :initialize do |_db, sql|
|
37
|
+
Helpers.scan(sql, "statement.execute")
|
38
|
+
end
|
39
|
+
end
|
43
40
|
end
|
44
41
|
end
|
45
42
|
end
|
@@ -3,14 +3,6 @@
|
|
3
3
|
module Aikido::Zen
|
4
4
|
module Sinks
|
5
5
|
module Trilogy
|
6
|
-
def self.load_sinks!
|
7
|
-
if Aikido::Zen.satisfy "trilogy", ">= 2.0"
|
8
|
-
require "trilogy"
|
9
|
-
|
10
|
-
::Trilogy.prepend(TrilogyExtensions)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
6
|
SINK = Sinks.add("trilogy", scanners: [Scanners::SQLInjectionScanner])
|
15
7
|
|
16
8
|
module Helpers
|
@@ -19,11 +11,17 @@ module Aikido::Zen
|
|
19
11
|
end
|
20
12
|
end
|
21
13
|
|
22
|
-
|
23
|
-
|
14
|
+
def self.load_sinks!
|
15
|
+
if Aikido::Zen.satisfy "trilogy", ">= 2.0"
|
16
|
+
require "trilogy"
|
17
|
+
|
18
|
+
::Trilogy.class_eval do
|
19
|
+
extend Sinks::DSL
|
24
20
|
|
25
|
-
|
26
|
-
|
21
|
+
sink_before :query do |query|
|
22
|
+
Helpers.scan(query, "query")
|
23
|
+
end
|
24
|
+
end
|
27
25
|
end
|
28
26
|
end
|
29
27
|
end
|
data/lib/aikido/zen/sinks.rb
CHANGED
@@ -9,10 +9,7 @@ require_relative "sinks_dsl"
|
|
9
9
|
|
10
10
|
require_relative "sinks/action_controller" if defined?(::ActionController)
|
11
11
|
|
12
|
-
|
13
|
-
# Kernel module because how the `prepend` method is applied
|
14
|
-
# (https://stackoverflow.com/questions/78110397/prepend-kernel-module-function-globally#comment137713906_78112924)
|
15
|
-
require_relative "sinks/kernel" if RUBY_VERSION >= "3.0"
|
12
|
+
require_relative "sinks/kernel"
|
16
13
|
|
17
14
|
require_relative "sinks/file"
|
18
15
|
require_relative "sinks/socket"
|
data/lib/aikido/zen/sinks_dsl.rb
CHANGED
@@ -109,10 +109,14 @@ module Aikido::Zen
|
|
109
109
|
#
|
110
110
|
# @return [void]
|
111
111
|
def presafe_sink_before(method_name, &block)
|
112
|
+
original = instance_method(method_name)
|
113
|
+
|
112
114
|
define_method(method_name) do |*args, **kwargs, &blk|
|
113
115
|
instance_exec(*args, **kwargs, &block)
|
114
|
-
|
116
|
+
original.bind_call(self, *args, **kwargs, &blk)
|
115
117
|
end
|
118
|
+
rescue NameError
|
119
|
+
Aikido::Zen.config.logger.warn("cannot wrap method `#{method_name}' for class `#{self}'")
|
116
120
|
end
|
117
121
|
|
118
122
|
# Define a method `method_name` that safely executes the given block before
|
@@ -145,11 +149,15 @@ module Aikido::Zen
|
|
145
149
|
#
|
146
150
|
# @return [void]
|
147
151
|
def presafe_sink_after(method_name, &block)
|
152
|
+
original = instance_method(method_name)
|
153
|
+
|
148
154
|
define_method(method_name) do |*args, **kwargs, &blk|
|
149
|
-
result =
|
155
|
+
result = original.bind_call(self, *args, **kwargs, &blk)
|
150
156
|
instance_exec(result, *args, **kwargs, &block)
|
151
157
|
result
|
152
158
|
end
|
159
|
+
rescue NameError
|
160
|
+
Aikido::Zen.config.logger.warn("cannot wrap method `#{method_name}' for class `#{self}'")
|
153
161
|
end
|
154
162
|
|
155
163
|
# Define a method `method_name` that safely executes the given block after
|
@@ -177,20 +185,24 @@ module Aikido::Zen
|
|
177
185
|
#
|
178
186
|
# @param method_name [Symbol, String] the name of the method to define
|
179
187
|
# @yield the block to execute around the original method
|
180
|
-
# @yieldparam
|
188
|
+
# @yieldparam original_call [Proc] the proc that calls the original method
|
181
189
|
# @yieldparam args [Array] the positional arguments passed to the original method
|
182
190
|
# @yieldparam kwargs [Hash] the keyword arguments passed to the original method
|
183
191
|
#
|
184
192
|
# @return [void]
|
185
193
|
def presafe_sink_around(method_name, &block)
|
194
|
+
original = instance_method(method_name)
|
195
|
+
|
186
196
|
define_method(method_name) do |*args, **kwargs, &blk|
|
187
197
|
result = nil
|
188
|
-
|
189
|
-
result =
|
198
|
+
original_call = proc do
|
199
|
+
result = original.bind_call(self, *args, **kwargs, &blk)
|
190
200
|
end
|
191
|
-
instance_exec(
|
201
|
+
instance_exec(original_call, *args, **kwargs, &block)
|
192
202
|
result
|
193
203
|
end
|
204
|
+
rescue NameError
|
205
|
+
Aikido::Zen.config.logger.warn("cannot wrap method `#{method_name}' for class `#{self}'")
|
194
206
|
end
|
195
207
|
|
196
208
|
# Define a method `method_name` that safely executes the given block around
|
@@ -198,27 +210,27 @@ module Aikido::Zen
|
|
198
210
|
#
|
199
211
|
# @param method_name [Symbol, String] the name of the method to define
|
200
212
|
# @yield the block to execute around the original method
|
201
|
-
# @yieldparam
|
213
|
+
# @yieldparam original_call [Proc] the proc that calls the original method
|
202
214
|
# @yieldparam args [Array] the positional arguments passed to the original method
|
203
215
|
# @yieldparam kwargs [Hash] the keyword arguments passed to the original method
|
204
216
|
#
|
205
217
|
# @return [void]
|
206
218
|
#
|
207
219
|
# @note the block is executed within `safe` to handle errors safely; the original method is executed within `presafe` to preserve the original behavior
|
208
|
-
# @note if the block does not call `
|
220
|
+
# @note if the block does not call `original_call`, the original method is called automatically after the block is executed
|
209
221
|
def sink_around(method_name, &block)
|
210
|
-
presafe_sink_around(method_name) do |
|
211
|
-
|
212
|
-
|
213
|
-
|
222
|
+
presafe_sink_around(method_name) do |presafe_original_call, *args, **kwargs|
|
223
|
+
original_called = false
|
224
|
+
original_call = proc do
|
225
|
+
original_called = true
|
214
226
|
DSL.presafe do
|
215
|
-
|
227
|
+
presafe_original_call.call
|
216
228
|
end
|
217
229
|
end
|
218
230
|
DSL.safe do
|
219
|
-
instance_exec(
|
231
|
+
instance_exec(original_call, *args, **kwargs, &block)
|
220
232
|
end
|
221
|
-
|
233
|
+
presafe_original_call.call unless original_called
|
222
234
|
end
|
223
235
|
end
|
224
236
|
end
|
data/lib/aikido/zen/version.rb
CHANGED
data/lib/aikido/zen.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# IMPORTANT: Any files that load sinks or start the Aikido Agent should
|
4
|
-
# be required in `Aikido::Zen.protect!`.
|
5
|
-
|
6
3
|
require_relative "zen/version"
|
7
4
|
require_relative "zen/errors"
|
8
5
|
require_relative "zen/actor"
|
@@ -29,6 +26,9 @@ module Aikido
|
|
29
26
|
# Enable protection. Until this method is called no sinks are loaded
|
30
27
|
# and the Aikido Agent does not start.
|
31
28
|
#
|
29
|
+
# This method should be called only once, in the application after the
|
30
|
+
# initialization process is complete.
|
31
|
+
#
|
32
32
|
# @return [void]
|
33
33
|
def self.protect!
|
34
34
|
if config.disabled?
|
@@ -36,16 +36,14 @@ module Aikido
|
|
36
36
|
return
|
37
37
|
end
|
38
38
|
|
39
|
-
|
40
|
-
# should be required here only.
|
39
|
+
return unless config.protect?
|
41
40
|
|
42
|
-
|
43
|
-
|
41
|
+
unless load_sources! && load_sinks!
|
42
|
+
config.logger.warn("Zen could not find any supported libraries or frameworks. Visit https://github.com/AikidoSec/firewall-ruby for more information.")
|
43
|
+
return
|
44
44
|
end
|
45
45
|
|
46
|
-
|
47
|
-
warn "Zen could not find any supported libraries or frameworks. Visit https://github.com/AikidoSec/firewall-ruby for more information."
|
48
|
-
end
|
46
|
+
middleware_installed!
|
49
47
|
end
|
50
48
|
|
51
49
|
# @!visibility private
|
@@ -173,15 +171,28 @@ module Aikido
|
|
173
171
|
collector.middleware_installed!
|
174
172
|
end
|
175
173
|
|
176
|
-
#
|
177
|
-
#
|
178
|
-
# at the end of the initialization process).
|
174
|
+
# @!visibility private
|
175
|
+
# Load all sources.
|
179
176
|
#
|
180
|
-
#
|
177
|
+
# @return [Boolean] true if any sources were loaded
|
178
|
+
def self.load_sources!
|
179
|
+
if Aikido::Zen.satisfy("rails", ">= 7.0")
|
180
|
+
require_relative "zen/rails_engine"
|
181
|
+
|
182
|
+
return true
|
183
|
+
end
|
184
|
+
|
185
|
+
false
|
186
|
+
end
|
187
|
+
|
188
|
+
# @!visibility private
|
189
|
+
# Load all sinks.
|
181
190
|
#
|
182
|
-
# @return [
|
191
|
+
# @return [Boolean] true if any sinks were loaded
|
183
192
|
def self.load_sinks!
|
184
193
|
require_relative "zen/sinks"
|
194
|
+
|
195
|
+
!Aikido::Zen::Sinks.registry.empty?
|
185
196
|
end
|
186
197
|
|
187
198
|
# @!visibility private
|
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: 1.0.1.beta.
|
4
|
+
version: 1.0.1.beta.5
|
5
5
|
platform: arm64-darwin
|
6
6
|
authors:
|
7
7
|
- Aikido Security
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-08-
|
11
|
+
date: 2025-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|