image_processing 2.0.2 → 2.0.3

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: 5a11a590332eebc08eff9b2cc0ff0436ff8ab42c6bee6e85034232d8e5425700
4
- data.tar.gz: 983201e5b89000e91f299f4f25cfa861673e6a552f5f751d336bf45b12f3b534
3
+ metadata.gz: 073bdcd7bc5e6fbb52b92f70de43d3b700316620dd23ec75b9aeac18bd5375b3
4
+ data.tar.gz: 1678df6fd73afc2230fafd9c3f84b2d5174351819ef0f3961ed5206f2c6ae53b
5
5
  SHA512:
6
- metadata.gz: 762c39caba0bfba8f5b00eb3334308a0a3fd79f602301e087cc7e53acb38dc416ad8bd547d6779636c966c25fbf689c75d306394ca01a93d8dfe13e5fb902ac6
7
- data.tar.gz: 94e92fff8dddd41a3651ee85e58bdcdc94d293fbacf573e62a2ca560ad9c5546f9e79e9e97736948b7daf65478938e15e2e7ffa8a4d7f8a6b55a7ed24e930f14
6
+ metadata.gz: e41739ac97beb0cb48cd97be766578cac1c14b4fd86fea0dd7401b835ecfbd2c018485d12ea0cb6d3c6cfcf0d4e0355d5c011770dd7f0c74aec26e7499cb306f
7
+ data.tar.gz: 7618aa5091de6ddc2a01a189e548e508d862535ad8a7f4e400845c8696fcace78081f33efc343fa220ed04d13a0a71106a7e7c10141c107764270640ad30a0a6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 2.0.3 (2026-06-08)
2
+
3
+ * Prevent remote code execution when operation names come from user input, closing bypasses through the `#operation` meta-builder, `#method_missing`, and nested `#send` calls (reported by @szymonsec)
4
+
5
+ * [minimagick] Prevent remote code execution through unsafe public methods (e.g. `#instance_eval`, `#send`) passed as loader/saver option names
6
+
1
7
  ## 2.0.2 (2026-06-03)
2
8
 
3
9
  * Raise `LoadError` instead of `ImageProcessing::Error` when soft dependencies are missing (@bdewater-thatch)
@@ -86,25 +86,24 @@ module ImageProcessing
86
86
  private
87
87
 
88
88
  # This prevents calling unsafe Ruby core methods such as `Kernel#system`,
89
- # which would allow for remote shell execution.
89
+ # which would allow for remote shell execution. The processor enforces the
90
+ # same guard when operations are dispatched, which also covers paths that
91
+ # bypass this early check (e.g. the #operation meta-builder).
92
+ #
93
+ # Bang names are rejected here because they are Chainable's execution
94
+ # shortcut (see #method_missing), not operations to chain.
90
95
  def invalid_operation?(name)
91
- return true if name.end_with?("!")
92
-
93
- owner = method(name).owner
94
- [BasicObject, Kernel, Object, Module].include?(owner)
95
- rescue NameError
96
- false
96
+ name.end_with?("!") || ImageProcessing.unsafe_method?(self, name)
97
97
  end
98
98
 
99
99
  # Assume that any unknown method names an operation supported by the
100
100
  # processor. Add a bang ("!") if you want processing to be performed.
101
- def method_missing(name, *args, &block)
102
- return super if name.to_s.end_with?("?")
103
- return public_send(name.to_s.chomp("!"), *args, &block).call if name.to_s.end_with?("!")
101
+ def method_missing(name, ...)
102
+ return super if name.end_with?("?")
103
+ return public_send(name.to_s.chomp("!"), ...).call if name.end_with?("!")
104
104
 
105
- operation(name, *args, &block)
105
+ operation(name, ...)
106
106
  end
107
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
108
107
 
109
108
  # Empty options which the builder starts with.
110
109
  DEFAULT_OPTIONS = {
@@ -225,6 +225,13 @@ module ImageProcessing
225
225
  # Applies options from the provided hash.
226
226
  def apply_options(magick, define: {}, **options)
227
227
  options.each do |option, value|
228
+ # Loader/saver option names may come from user input, so guard
229
+ # against dispatching to unsafe Ruby core methods (e.g. #send,
230
+ # #instance_eval) that public_send does not block on its own.
231
+ if ImageProcessing.unsafe_method?(magick, option)
232
+ raise Error, "#{option.inspect} is not a valid option"
233
+ end
234
+
228
235
  case value
229
236
  when true, nil then magick.public_send(option)
230
237
  when false then magick.public_send(option).+
@@ -53,6 +53,15 @@ module ImageProcessing
53
53
  # operation directly on the accumulator object. This provides a common
54
54
  # umbrella above defined macros and direct operations.
55
55
  def apply_operation(name, *args, &block)
56
+ # Chainable performs the same check when operations are built, but that
57
+ # guard only sees the outer builder method name, so it can be routed
58
+ # around via the #operation meta-builder, #method_missing, or a nested
59
+ # #send. This is the single point every operation is finally dispatched
60
+ # through, so enforcing the guard here closes all of those paths.
61
+ if ImageProcessing.unsafe_method?(self, name)
62
+ fail Error, "#{name.inspect} is not a valid operation"
63
+ end
64
+
56
65
  receiver = respond_to?(name) ? self : @accumulator
57
66
 
58
67
  if args.last.is_a?(Hash)
@@ -1,3 +1,3 @@
1
1
  module ImageProcessing
2
- VERSION = "2.0.2"
2
+ VERSION = "2.0.3"
3
3
  end
@@ -7,6 +7,25 @@ require "image_processing/version"
7
7
  module ImageProcessing
8
8
  Error = Class.new(StandardError)
9
9
 
10
+ # Method owners considered unsafe to dispatch to when a method name comes
11
+ # from user input, because they expose Ruby's metaprogramming and shell
12
+ # primitives (e.g. Kernel#send, Kernel#eval, BasicObject#instance_eval,
13
+ # Kernel#system). Any name whose implementation is inherited from one of
14
+ # these should never be treated as an image operation or a loader/saver
15
+ # option.
16
+ UNSAFE_METHOD_OWNERS = [BasicObject, Kernel, Object, Module].freeze
17
+
18
+ # Whether calling +name+ on +receiver+ would dispatch to an unsafe Ruby core
19
+ # method rather than a genuine operation. Used as a single, shared guard at
20
+ # every place where a user-provided name is dispatched via +public_send+.
21
+ def self.unsafe_method?(receiver, name)
22
+ UNSAFE_METHOD_OWNERS.include?(receiver.method(name.to_s).owner)
23
+ rescue NameError
24
+ # An unknown name is not a Ruby core method, so it is safe to forward to
25
+ # the receiver (which will reject it if it is not a real operation).
26
+ false
27
+ end
28
+
10
29
  autoload :MiniMagick, "image_processing/mini_magick"
11
30
  autoload :Vips, "image_processing/vips"
12
31
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: image_processing
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  - !ruby/object:Gem::Version
106
106
  version: '0'
107
107
  requirements: []
108
- rubygems_version: 4.0.3
108
+ rubygems_version: 4.0.13
109
109
  specification_version: 4
110
110
  summary: High-level wrapper for processing images for the web with ImageMagick or
111
111
  libvips.