aikido-zen 1.7.2.beta.2 → 1.7.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aedfb64ca08c10194c0483138460f984e086ad2ac95250d3ce570b4c08b48263
4
- data.tar.gz: 6332c4155469c35483394a76683169e973feea9ba417fb4c4f434f8df3231b2e
3
+ metadata.gz: 41f1982e134a806c513cc166247059c3f290f6bbc88ff32dcf4bdc65da9f377d
4
+ data.tar.gz: d97dac2f830555239836a143b815ca3c85c4993776183ce73bc5dc392fed9618
5
5
  SHA512:
6
- metadata.gz: 97a1b03ca7b5b92d944793c650f11791f7a36794e5ebcc85c6c41e6a93f71c1fbab3a5e32f0beeae6254c89ea06f23535275f20cc3732f18c8db722e4b6ec482
7
- data.tar.gz: 35ba0d4afe57aba7dac30c89294a875779fba9f36413c1c335d97efb62a47b5d3beaa8c5b96d31a9dda491d89b2dd0a78851a4d5ca83dd34071732c981d92b56
6
+ metadata.gz: 526140c45a47c29f4f36e1508bc3305bafe535e92479c877deeb92a1f74c618fa19d7c46a7d67183310fbc414f05912b93c88f2cdb109730d04c0b4b6a54b301
7
+ data.tar.gz: 6c43bc7461a52ded8331b6ba2188afd9d273e1b012f5912b2d9786c439e2890380003779925bd3f37fdd4422f4b34aefe13af6d29d0a6a7f3b4e351c5019dca1
@@ -0,0 +1,38 @@
1
+ # Bypass Zen for a specific request
2
+
3
+ To disable Zen for a specific request, call `Aikido::Zen.request_bypassed!` from a Rack middleware. This bypasses Zen's security checks and stats collection for that request.
4
+
5
+ > [!NOTE]
6
+ > Zen already has a built-in feature for bypassing specific IP addresses. This feature offers more flexibility, letting you bypass Zen for a request based on any criteria you choose.
7
+
8
+ `Aikido::Zen.request_bypassed!` needs the request's context to already be set up, so your middleware must run after Zen's `ContextSetter` middleware. The following example shows how to bypass a specific request in a Rails application:
9
+
10
+ ```ruby
11
+ # config/application.rb
12
+ class RequestBypasser
13
+ def initialize(app)
14
+ @app = app
15
+ end
16
+
17
+ def call(env)
18
+ if your_custom_logic?(env)
19
+ Aikido::Zen.request_bypassed! # Bypasses Zen for this request
20
+ end
21
+
22
+ @app.call(env)
23
+ end
24
+ end
25
+
26
+ module YourApp
27
+ class Application < Rails::Application
28
+ # ...
29
+
30
+ initializer "your_app.insert_request_bypasser", after: "aikido.add_middleware" do |app|
31
+ app.middleware.insert_after Aikido::Zen::Middleware::ContextSetter, RequestBypasser
32
+ end
33
+ end
34
+ end
35
+ ```
36
+
37
+ > [!WARNING]
38
+ > Use this feature with caution, as it can potentially expose your application to security risks if not used properly.
@@ -24,6 +24,10 @@ module Aikido::Zen
24
24
  attr_accessor :scanning
25
25
  alias_method :scanning?, :scanning
26
26
 
27
+ # @return [Boolean, nil] whether the request is bypassed.
28
+ attr_accessor :request_bypassed
29
+ alias_method :request_bypassed?, :request_bypassed
30
+
27
31
  # @return [Boolean] whether attack protection for the currently requested
28
32
  # endpoint was disabled on the Aikido dashboard, or if the source IP for
29
33
  # this request is in the "Bypass List".
@@ -48,6 +52,7 @@ module Aikido::Zen
48
52
 
49
53
  @metadata = {}
50
54
  @scanning = false
55
+ @request_bypassed = nil
51
56
  @protection_disabled = false
52
57
  @idor_protection_enabled = false
53
58
  end
@@ -5,8 +5,9 @@ module Aikido::Zen
5
5
  # Middleware that only allows allowed IPs when allowed IPs are configured for
6
6
  # any matching route in the Aikido dashboard.
7
7
  class AllowedAddressChecker
8
- def initialize(app, config: Aikido::Zen.config, settings: Aikido::Zen.runtime_settings)
8
+ def initialize(app, zen: Aikido::Zen, config: zen.config, settings: zen.runtime_settings)
9
9
  @app = app
10
+ @zen = zen
10
11
  @config = config
11
12
  @settings = settings
12
13
  end
@@ -22,7 +23,7 @@ module Aikido::Zen
22
23
  end
23
24
 
24
25
  private def allowed?(request)
25
- return true if @settings.bypassed_ips.include?(request.client_ip)
26
+ return true if @zen.request_bypassed?
26
27
 
27
28
  matches = @settings.endpoints.matched_settings(request.route)
28
29
 
@@ -19,7 +19,7 @@ module Aikido::Zen
19
19
  end
20
20
 
21
21
  private def protection_disabled?(request)
22
- return true if @settings.bypassed_ips.include?(request.client_ip)
22
+ return true if @zen.request_bypassed?
23
23
 
24
24
  !@settings.endpoints.matched_settings(request.route).all?(&:protected?)
25
25
  end
@@ -4,10 +4,9 @@ module Aikido
4
4
  module Zen
5
5
  module Middleware
6
6
  class AttackWaveProtector
7
- def initialize(app, zen: Aikido::Zen, settings: Aikido::Zen.runtime_settings)
7
+ def initialize(app, zen: Aikido::Zen)
8
8
  @app = app
9
9
  @zen = zen
10
- @settings = settings
11
10
  end
12
11
 
13
12
  def call(env)
@@ -30,7 +29,7 @@ module Aikido
30
29
  request = context.request
31
30
  return nil if request.nil?
32
31
 
33
- return nil if @settings.bypassed_ips.include?(request.client_ip)
32
+ return nil if @zen.request_bypassed?
34
33
 
35
34
  @zen.detect_attack_wave(context, status_code)
36
35
  end
@@ -15,7 +15,7 @@ module Aikido::Zen
15
15
 
16
16
  client_ip = request.client_ip
17
17
 
18
- return @app.call(env) if bypassed_ip?(client_ip)
18
+ return @app.call(env) if @zen.request_bypassed?
19
19
 
20
20
  if !@settings.allowed_ip?(client_ip)
21
21
  return @config.blocked_responder.call(request, :ip_allowed_list)
@@ -38,10 +38,6 @@ module Aikido::Zen
38
38
 
39
39
  @app.call(env)
40
40
  end
41
-
42
- def bypassed_ip?(client_ip)
43
- @settings.bypassed_ips.include?(client_ip)
44
- end
45
41
  end
46
42
  end
47
43
  end
@@ -34,7 +34,7 @@ module Aikido::Zen
34
34
  private
35
35
 
36
36
  def should_throttle?(request)
37
- return false if @settings.bypassed_ips.include?(request.client_ip)
37
+ return false if @zen.request_bypassed?
38
38
 
39
39
  return false if request.actor && @settings.user_excluded_from_rate_limiting?(request.actor.id)
40
40
 
@@ -5,8 +5,9 @@ module Aikido::Zen
5
5
  # Rack middleware used to track request
6
6
  # It implements the logic under that which is considered worthy of being tracked.
7
7
  class RequestTracker
8
- def initialize(app, settings: Aikido::Zen.runtime_settings)
8
+ def initialize(app, zen: Aikido::Zen, settings: zen.runtime_settings)
9
9
  @app = app
10
+ @zen = zen
10
11
  @settings = settings
11
12
  end
12
13
 
@@ -17,13 +18,12 @@ module Aikido::Zen
17
18
  if request.route && track?(
18
19
  status_code: response[0],
19
20
  route: request.route.path,
20
- http_method: request.request_method,
21
- ip: request.client_ip
21
+ http_method: request.request_method
22
22
  )
23
- Aikido::Zen.track_request(request)
23
+ @zen.track_request(request)
24
24
 
25
- if Aikido::Zen.config.collect_api_schema?
26
- Aikido::Zen.track_discovered_route(request)
25
+ if @zen.config.collect_api_schema?
26
+ @zen.track_discovered_route(request)
27
27
  end
28
28
  end
29
29
 
@@ -128,8 +128,8 @@ module Aikido::Zen
128
128
  # @param status_code [Integer]
129
129
  # @param route [String]
130
130
  # @param http_method [String]
131
- def track?(status_code:, route:, http_method:, ip: nil)
132
- return false if @settings.bypassed_ips.include?(ip)
131
+ def track?(status_code:, route:, http_method:)
132
+ return false if @zen.request_bypassed?
133
133
 
134
134
  # In the UI we want to show only successful (2xx) or redirect (3xx) responses
135
135
  # anything else is discarded.
@@ -13,7 +13,7 @@ module Aikido::Zen
13
13
  def call(env)
14
14
  request = Aikido::Zen::Middleware.request_from(env)
15
15
 
16
- return @app.call(env) if bypassed?(request)
16
+ return @app.call(env) if @zen.request_bypassed?
17
17
 
18
18
  user_agent = request.user_agent
19
19
 
@@ -31,10 +31,6 @@ module Aikido::Zen
31
31
 
32
32
  @app.call(env)
33
33
  end
34
-
35
- def bypassed?(request)
36
- @settings.bypassed_ips.include?(request.client_ip)
37
- end
38
34
  end
39
35
  end
40
36
  end
@@ -30,7 +30,7 @@ module Aikido::Zen
30
30
 
31
31
  request = context.request
32
32
 
33
- return false if @settings.bypassed_ips.include?(request.client_ip)
33
+ return false if @zen.request_bypassed?
34
34
 
35
35
  if should_block_user?(request)
36
36
  status, headers, body = @config.blocked_responder.call(request, :user)
@@ -52,9 +52,7 @@ module Aikido::Zen
52
52
 
53
53
  settings = Aikido::Zen.runtime_settings
54
54
 
55
- client_ip = context&.request&.client_ip
56
-
57
- unless settings.bypassed_ip?(client_ip)
55
+ unless Aikido::Zen.request_bypassed?
58
56
  Aikido::Zen.track_outbound(connection)
59
57
 
60
58
  if settings.block_outbound?(connection)
@@ -64,9 +64,7 @@ module Aikido::Zen
64
64
 
65
65
  settings = Aikido::Zen.runtime_settings
66
66
 
67
- client_ip = context&.request&.client_ip
68
-
69
- unless settings.bypassed_ip?(client_ip)
67
+ unless Aikido::Zen.request_bypassed?
70
68
  Aikido::Zen.track_outbound(connection)
71
69
 
72
70
  if settings.block_outbound?(connection)
@@ -50,9 +50,7 @@ module Aikido::Zen
50
50
 
51
51
  settings = Aikido::Zen.runtime_settings
52
52
 
53
- client_ip = context&.request&.client_ip
54
-
55
- unless settings.bypassed_ip?(client_ip)
53
+ unless Aikido::Zen.request_bypassed?
56
54
  Aikido::Zen.track_outbound(connection)
57
55
 
58
56
  if settings.block_outbound?(connection)
@@ -56,9 +56,7 @@ module Aikido::Zen
56
56
 
57
57
  settings = Aikido::Zen.runtime_settings
58
58
 
59
- client_ip = context&.request&.client_ip
60
-
61
- unless settings.bypassed_ip?(client_ip)
59
+ unless Aikido::Zen.request_bypassed?
62
60
  Aikido::Zen.track_outbound(connection)
63
61
 
64
62
  if settings.block_outbound?(connection)
@@ -70,9 +70,7 @@ module Aikido::Zen
70
70
 
71
71
  settings = Aikido::Zen.runtime_settings
72
72
 
73
- client_ip = context&.request&.client_ip
74
-
75
- unless settings.bypassed_ip?(client_ip)
73
+ unless Aikido::Zen.request_bypassed?
76
74
  Aikido::Zen.track_outbound(connection)
77
75
 
78
76
  if settings.block_outbound?(connection)
@@ -50,9 +50,7 @@ module Aikido::Zen
50
50
 
51
51
  settings = Aikido::Zen.runtime_settings
52
52
 
53
- client_ip = context&.request&.client_ip
54
-
55
- unless settings.bypassed_ip?(client_ip)
53
+ unless Aikido::Zen.request_bypassed?
56
54
  Aikido::Zen.track_outbound(connection)
57
55
 
58
56
  if settings.block_outbound?(connection)
@@ -55,9 +55,7 @@ module Aikido::Zen
55
55
 
56
56
  settings = Aikido::Zen.runtime_settings
57
57
 
58
- client_ip = context&.request&.client_ip
59
-
60
- unless settings.bypassed_ip?(client_ip)
58
+ unless Aikido::Zen.request_bypassed?
61
59
  Aikido::Zen.track_outbound(connection)
62
60
 
63
61
  if settings.block_outbound?(connection)
@@ -86,9 +86,7 @@ module Aikido::Zen
86
86
 
87
87
  settings = Aikido::Zen.runtime_settings
88
88
 
89
- client_ip = context&.request&.client_ip
90
-
91
- unless settings.bypassed_ip?(client_ip)
89
+ unless Aikido::Zen.request_bypassed?
92
90
  Aikido::Zen.track_outbound(connection)
93
91
 
94
92
  if settings.block_outbound?(connection)
@@ -59,9 +59,7 @@ module Aikido::Zen
59
59
 
60
60
  settings = Aikido::Zen.runtime_settings
61
61
 
62
- client_ip = context&.request&.client_ip
63
-
64
- unless settings.bypassed_ip?(client_ip)
62
+ unless Aikido::Zen.request_bypassed?
65
63
  Aikido::Zen.track_outbound(connection)
66
64
 
67
65
  if settings.block_outbound?(connection)
@@ -26,9 +26,7 @@ module Aikido::Zen
26
26
 
27
27
  settings = Aikido::Zen.runtime_settings
28
28
 
29
- client_ip = context&.request&.client_ip
30
-
31
- unless settings.bypassed_ip?(client_ip)
29
+ unless Aikido::Zen.request_bypassed?
32
30
  Aikido::Zen.track_outbound(connection)
33
31
 
34
32
  if settings.block_outbound?(connection)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Aikido
4
4
  module Zen
5
- VERSION = "1.7.2.beta.2"
5
+ VERSION = "1.7.2"
6
6
 
7
7
  # The version of libzen_internals that we build against.
8
8
  LIBZEN_VERSION = "0.1.61"
data/lib/aikido/zen.rb CHANGED
@@ -153,6 +153,23 @@ module Aikido
153
153
  Fiber.current.aikido_current_context = context
154
154
  end
155
155
 
156
+ # @return [Boolean] whether the current request is bypassed.
157
+ def self.request_bypassed?
158
+ context = current_context
159
+ return unless context
160
+
161
+ return context.request_bypassed unless context.request_bypassed.nil?
162
+
163
+ context.request_bypassed = runtime_settings.bypassed_ip?(context.request.client_ip)
164
+ end
165
+
166
+ # Marks the current request as bypassed.
167
+ #
168
+ # @return [void]
169
+ def self.request_bypassed!
170
+ current_context&.request_bypassed = true
171
+ end
172
+
156
173
  # Track statistics about an HTTP request the app is handling.
157
174
  #
158
175
  # @param request [Aikido::Zen::Request]
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.7.2.beta.2
4
+ version: 1.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aikido Security
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-14 00:00:00.000000000 Z
11
+ date: 2026-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -93,6 +93,7 @@ files:
93
93
  - docs/invalid-sql-queries.md
94
94
  - docs/proxy.md
95
95
  - docs/rails.md
96
+ - docs/request-bypassing.md
96
97
  - docs/troubleshooting.md
97
98
  - lib/aikido-zen.rb
98
99
  - lib/aikido/zen.rb