Fix command injection via Symbol arguments in net-imap.

Fixes CVE-2026-42258.

Tests not included, the gem does not have tests in the ruby tar.
Original source PR#663 but it bunches more fixes together, so we backport less.

https://github.com/ruby/net-imap/pull/663

Backported from the following, the first commit below is requirement for the actual fix:
1eb27278a6
bbd9eb7ecc

Resolves: RHEL-181799
This commit is contained in:
Jarek Prokop 2026-06-11 16:31:18 +02:00
parent dac8422aaf
commit 37db3a8398
2 changed files with 219 additions and 0 deletions

View File

@ -310,6 +310,13 @@ Patch18: rubygem-net-imap-0.4.24-DoS-via-crafted-IMAP-responses-CVE-2026-42245.p
# https://github.com/ruby/net-imap/commit/705aa59
# https://github.com/ruby/net-imap/commit/038ae35
Patch19: rubygem-net-imap-0.4.24-Information-disclosure-via-MITM-attack-bypassing-TLS-2026-42246.patch
# Tests not included, the gem does not have tests in the ruby tar.
# Original source PR#663 but it bunches more fixes together, so we backport less.
# https://github.com/ruby/net-imap/pull/663
# Backported from the following, the first commit below is requirement for the actual fix:
# https://github.com/ruby/net-imap/commit/1eb27278a601be1135910dae6ab6e517559a2e4a
# https://github.com/ruby/net-imap/commit/bbd9eb7ecca506fa43b656368f7aebef8ac09182
Patch20: rubygem-net-imap-0.4.24-Command-Injection-via-Symbol-Arguments-CVE-2026-42258.patch
Requires: %{name}-libs%{?_isa} = %{version}-%{release}
%{?with_rubypick:Suggests: rubypick}
@ -798,6 +805,7 @@ analysis result in RBS format, a standard type description format for Ruby
pushd .bundle/gems/net-imap-%{net_imap_version}
%patch 18 -p1
%patch 19 -p1
%patch 20 -p1
popd
# Provide an example of usage of the tapset:
@ -1810,6 +1818,8 @@ make -C %{_vpath_builddir} runruby TESTRUN_SCRIPT=" \
- Fix information disclosure via MITM attack bypassing TLS in net-imap.
(CVE-2026-42246)
Resolves: RHEL-181769
- Fix command injection via Symbol arguments in net-imap. (CVE-2026-42258)
Resolves: RHEL-181799
* Tue Apr 28 2026 Jarek Prokop <jprokop@redhat.com> - 3.3.10-12
- Fix arbitrary code execution via deserialization bypass in ERB. (CVE-2026-41316)

View File

@ -0,0 +1,209 @@
From e55d73b170eb4a5523a411cdc9bd5cf13121694e Mon Sep 17 00:00:00 2001
From: nick evans <nick@rubinick.dev>
Date: Wed, 22 Apr 2026 11:25:06 -0400
Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=8D=92=20edit=20ca72ac45:=20=E2=99=BB?=
=?UTF-8?q?=EF=B8=8F=20Extract=20superclass=20for=20(internal)=20command?=
=?UTF-8?q?=20data?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Unlike the cherry-picked commit (ca72ac45), this _only_ makes
`CommandData` the superclass for `Literal` and `Atom`. Because those
are the classes that will be modified by later cherry-picked commits.
This allows those other commits to merge more cleanly, and work with
fewer modifications.
---
lib/net/imap/command_data.rb | 50 +++++++++++++++++++-----------------
1 file changed, 26 insertions(+), 24 deletions(-)
diff --git a/lib/net/imap/command_data.rb b/lib/net/imap/command_data.rb
index 180a254..91c7336 100644
--- a/lib/net/imap/command_data.rb
+++ b/lib/net/imap/command_data.rb
@@ -119,33 +119,44 @@ module Net
put_string("\\" + symbol.to_s)
end
- class RawData # :nodoc:
- def send_data(imap, tag)
- imap.__send__(:put_string, @data)
+ # simplistic emulation of CommandData = Data.define(:data)
+ class CommandData # :nodoc:
+ class << self
+ def new(arg = nil, data: arg) super(data: data) end
+ alias :[] :new
end
- def validate
+ def initialize(data:)
+ @data = data
+ freeze
end
- private
+ attr_reader :data
- def initialize(data)
- @data = data
- end
- end
+ def to_h(&block) block ? to_h.to_h(&block) : { data: data } end
+ def ==(other) self.class === other && to_h == other.to_h end
+ def eql?(other) self.class === other && to_h.eql?(other.to_h) end
+
+ # following class definition goes beyond the basic Data.define(:data)
+ ##
- class Atom # :nodoc:
def send_data(imap, tag)
- imap.__send__(:put_string, @data)
+ raise NoMethodError, "#{self.class} must implement #{__method__}"
end
def validate
end
+ end
- private
+ class RawData < CommandData # :nodoc:
+ def send_data(imap, tag)
+ imap.__send__(:put_string, @data)
+ end
+ end
- def initialize(data)
- @data = data
+ class Atom < CommandData # :nodoc:
+ def send_data(imap, tag)
+ imap.__send__(:put_string, @data)
end
end
@@ -164,19 +175,10 @@ module Net
end
end
- class Literal # :nodoc:
+ class Literal < CommandData # :nodoc:
def send_data(imap, tag)
imap.__send__(:send_literal, @data, tag)
end
-
- def validate
- end
-
- private
-
- def initialize(data)
- @data = data
- end
end
class MessageSet # :nodoc:
From d1c362631589b20e59f5e64fe1ee9222b3ea07f9 Mon Sep 17 00:00:00 2001
From: nick evans <nick@rubinick.dev>
Date: Thu, 19 Feb 2026 15:06:08 -0500
Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8D=92=20pick=209db3e9d60:=20?=
=?UTF-8?q?=F0=9F=A5=85=20Strictly=20validate=20symbol=20(\flag)=20argumen?=
=?UTF-8?q?ts=20[backports=20#657]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Flags should not allow `atom-specials`.
Previously, no validation was done on symbol data. Sending atom or flag
args which contain atom specials could lead to various errors.
Although this could theoretically include injection attacks, this is not
considered to be a critical vulnerability in `net-imap`, for the
following reason: Valid "system flag" inputs are restricted to an
enumerated set of RFC-defined flag types. User-defined "keyword" flags
are sent as atoms, not flags, which use string inputs (strings which
can't be sent as an atom will be quoted or sent as a literal). `\Seen`
as a flag (symbol argument) is semantically different from `Seen` as a
keyword (string argument). So there is no scenario where it is
appropriate to call `#to_sym` on unvetted user input. Any code which
calls `#to_sym` indiscriminately on user-input is already buggy.
Nevertheless, users should reasonably be able to rely on `net-imap` to
do very basic input validation on its basic input types.
---
lib/net/imap/command_data.rb | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/lib/net/imap/command_data.rb b/lib/net/imap/command_data.rb
index 91c7336..499002f 100644
--- a/lib/net/imap/command_data.rb
+++ b/lib/net/imap/command_data.rb
@@ -25,6 +25,7 @@ module Net
end
when Time, Date, DateTime
when Symbol
+ Flag.validate(data)
else
data.validate
end
@@ -45,7 +46,7 @@ module Net
when Date
send_date_data(data)
when Symbol
- send_symbol_data(data)
+ Flag[data].send_data(self, tag)
else
data.send_data(self, tag)
end
@@ -115,10 +116,6 @@ module Net
def send_date_data(date) put_string Net::IMAP.encode_date(date) end
def send_time_data(time) put_string Net::IMAP.encode_time(time) end
- def send_symbol_data(symbol)
- put_string("\\" + symbol.to_s)
- end
-
# simplistic emulation of CommandData = Data.define(:data)
class CommandData # :nodoc:
class << self
@@ -140,6 +137,12 @@ module Net
# following class definition goes beyond the basic Data.define(:data)
##
+ def self.validate(...)
+ data = new(...)
+ data.validate
+ data
+ end
+
def send_data(imap, tag)
raise NoMethodError, "#{self.class} must implement #{__method__}"
end
@@ -155,8 +158,26 @@ module Net
end
class Atom < CommandData # :nodoc:
+ def initialize(**)
+ super
+ validate
+ end
+
+ def validate
+ data.to_s.ascii_only? \
+ or raise DataFormatError, "#{self.class} must be ASCII only"
+ data.match?(ResponseParser::Patterns::ATOM_SPECIALS) \
+ and raise DataFormatError, "#{self.class} must not contain atom-specials"
+ end
+
def send_data(imap, tag)
- imap.__send__(:put_string, @data)
+ imap.__send__(:put_string, data.to_s)
+ end
+ end
+
+ class Flag < Atom # :nodoc:
+ def send_data(imap, tag)
+ imap.__send__(:put_string, "\\#{data}")
end
end