VYPR
Medium severity6.5NVD Advisory· Published Feb 10, 2025· Updated Apr 15, 2026

CVE-2025-25186

CVE-2025-25186

Description

Net::IMAP implements Internet Message Access Protocol (IMAP) client functionality in Ruby. Starting in version 0.3.2 and prior to versions 0.3.8, 0.4.19, and 0.5.6, there is a possibility for denial of service by memory exhaustion in net-imap's response parser. At any time while the client is connected, a malicious server can send can send highly compressed uid-set data which is automatically read by the client's receiver thread. The response parser uses Range#to_a to convert the uid-set data into arrays of integers, with no limitation on the expanded size of the ranges. Versions 0.3.8, 0.4.19, 0.5.6, and higher fix this issue. Additional details for proper configuration of fixed versions and backward compatibility are available in the GitHub Security Advisory.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
net-imapRubyGems
>= 0.3.2, < 0.3.80.3.8
net-imapRubyGems
>= 0.4.0, < 0.4.190.4.19
net-imapRubyGems
>= 0.5.0, < 0.5.60.5.6

Patches

6
c8c5a643739d

Merge commit from fork

https://github.com/ruby/net-imapnicholas a. evansFeb 7, 2025via ghsa
3 files changed · +108 4
  • lib/net/imap/config.rb+41 1 modified
    @@ -266,6 +266,12 @@ def self.[](config)
           # CopyUIDData for +COPYUID+ response codes, and UIDPlusData or
           # AppendUIDData for +APPENDUID+ response codes.
           #
    +      # UIDPlusData stores its data in arrays of numbers, which is vulnerable to
    +      # a memory exhaustion denial of service attack from an untrusted or
    +      # compromised server.  Set this option to +false+ to completely block this
    +      # vulnerability.  Otherwise, parser_max_deprecated_uidplus_data_size
    +      # mitigates this vulnerability.
    +      #
           # AppendUIDData and CopyUIDData are _mostly_ backward-compatible with
           # UIDPlusData.  Most applications should be able to upgrade with little
           # or no changes.
    @@ -282,12 +288,41 @@ def self.[](config)
           # [+true+ <em>(original default)</em>]
           #    ResponseParser only uses UIDPlusData.
           #
    +      # [+:up_to_max_size+ <em>(default since +v0.5.6+)</em>]
    +      #    ResponseParser uses UIDPlusData when the +uid-set+ size is below
    +      #    parser_max_deprecated_uidplus_data_size.  Above that size,
    +      #    ResponseParser uses AppendUIDData or CopyUIDData.
    +      #
           # [+false+ <em>(planned default for +v0.6+)</em>]
           #    ResponseParser _only_ uses AppendUIDData and CopyUIDData.
           attr_accessor :parser_use_deprecated_uidplus_data, type: [
    -        true, false
    +        true, :up_to_max_size, false
           ]
     
    +      # The maximum +uid-set+ size that ResponseParser will parse into
    +      # deprecated UIDPlusData.  This limit only applies when
    +      # parser_use_deprecated_uidplus_data is not +false+.
    +      #
    +      # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
    +      #
    +      # <em>Support for limiting UIDPlusData to a maximum size was added in
    +      # +v0.3.8+, +v0.4.19+, and +v0.5.6+.</em>
    +      #
    +      # <em>UIDPlusData will be removed in +v0.6+.</em>
    +      #
    +      # ==== Versioned Defaults
    +      #
    +      # Because this limit guards against a remote server causing catastrophic
    +      # memory exhaustion, the versioned default (used by #load_defaults) also
    +      # applies to versions without the feature.
    +      #
    +      # * +0.3+ and prior: <tt>10,000</tt>
    +      # * +0.4+: <tt>1,000</tt>
    +      # * +0.5+: <tt>100</tt>
    +      # * +0.6+: <tt>0</tt>
    +      #
    +      attr_accessor :parser_max_deprecated_uidplus_data_size, type: Integer
    +
           # Creates a new config object and initialize its attribute with +attrs+.
           #
           # If +parent+ is not given, the global config is used by default.
    @@ -368,6 +403,7 @@ def defaults_hash
             sasl_ir: true,
             responses_without_block: :silence_deprecation_warning,
             parser_use_deprecated_uidplus_data: true,
    +        parser_max_deprecated_uidplus_data_size: 1000,
           ).freeze
     
           @global = default.new
    @@ -377,6 +413,7 @@ def defaults_hash
           version_defaults[0] = Config[0.4].dup.update(
             sasl_ir: false,
             parser_use_deprecated_uidplus_data: true,
    +        parser_max_deprecated_uidplus_data_size: 10_000,
           ).freeze
           version_defaults[0.0] = Config[0]
           version_defaults[0.1] = Config[0]
    @@ -385,6 +422,8 @@ def defaults_hash
     
           version_defaults[0.5] = Config[0.4].dup.update(
             responses_without_block: :warn,
    +        parser_use_deprecated_uidplus_data: :up_to_max_size,
    +        parser_max_deprecated_uidplus_data_size: 100,
           ).freeze
     
           version_defaults[:default] = Config[0.4]
    @@ -394,6 +433,7 @@ def defaults_hash
           version_defaults[0.6]      = Config[0.5].dup.update(
             responses_without_block: :frozen_dup,
             parser_use_deprecated_uidplus_data: false,
    +        parser_max_deprecated_uidplus_data_size: 0,
           ).freeze
           version_defaults[:future]  = Config[0.6]
     
    
  • lib/net/imap/response_parser.rb+10 3 modified
    @@ -1889,9 +1889,16 @@ def CopyUID(...)   DeprecatedUIDPlus(...) || CopyUIDData.new(...)   end
           # TODO: remove this code in the v0.6.0 release
           def DeprecatedUIDPlus(validity, src_uids = nil, dst_uids)
             return unless config.parser_use_deprecated_uidplus_data
    -        src_uids &&= src_uids.each_ordered_number.to_a
    -        dst_uids   = dst_uids.each_ordered_number.to_a
    -        UIDPlusData.new(validity, src_uids, dst_uids)
    +        compact_uid_sets = [src_uids, dst_uids].compact
    +        count = compact_uid_sets.map { _1.count_with_duplicates }.max
    +        max   = config.parser_max_deprecated_uidplus_data_size
    +        if count <= max
    +          src_uids &&= src_uids.each_ordered_number.to_a
    +          dst_uids   = dst_uids.each_ordered_number.to_a
    +          UIDPlusData.new(validity, src_uids, dst_uids)
    +        elsif config.parser_use_deprecated_uidplus_data != :up_to_max_size
    +          parse_error("uid-set is too large: %d > %d", count, max)
    +        end
           end
     
           ADDRESS_REGEXP = /\G
    
  • test/net/imap/test_imap_response_parser.rb+57 0 modified
    @@ -205,16 +205,43 @@ def test_fetch_binary_and_binary_size
       test "APPENDUID with parser_use_deprecated_uidplus_data = true" do
         parser = Net::IMAP::ResponseParser.new(config: {
           parser_use_deprecated_uidplus_data:      true,
    +      parser_max_deprecated_uidplus_data_size: 10_000,
         })
    +    assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do
    +      parser.parse(
    +        "A004 OK [APPENDUID 1 10000:20000,1] Done\r\n"
    +      )
    +    end
    +    response = parser.parse("A004 OK [APPENDUID 1 100:200] Done\r\n")
    +    uidplus  = response.data.code.data
    +    assert_equal 101, uidplus.assigned_uids.size
    +    parser.config.parser_max_deprecated_uidplus_data_size = 100
    +    assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do
    +      parser.parse(
    +        "A004 OK [APPENDUID 1 100:200] Done\r\n"
    +      )
    +    end
         response = parser.parse("A004 OK [APPENDUID 1 101:200] Done\r\n")
         uidplus  = response.data.code.data
         assert_instance_of Net::IMAP::UIDPlusData, uidplus
         assert_equal 100, uidplus.assigned_uids.size
       end
     
    +  test "APPENDUID with parser_use_deprecated_uidplus_data = :up_to_max_size" do
    +    parser = Net::IMAP::ResponseParser.new(config: {
    +      parser_use_deprecated_uidplus_data:      :up_to_max_size,
    +      parser_max_deprecated_uidplus_data_size: 100
    +    })
    +    response = parser.parse("A004 OK [APPENDUID 1 101:200] Done\r\n")
    +    assert_instance_of Net::IMAP::UIDPlusData, response.data.code.data
    +    response = parser.parse("A004 OK [APPENDUID 1 100:200] Done\r\n")
    +    assert_instance_of Net::IMAP::AppendUIDData, response.data.code.data
    +  end
    +
       test "APPENDUID with parser_use_deprecated_uidplus_data = false" do
         parser = Net::IMAP::ResponseParser.new(config: {
           parser_use_deprecated_uidplus_data:      false,
    +      parser_max_deprecated_uidplus_data_size: 10_000_000,
         })
         response = parser.parse("A004 OK [APPENDUID 1 10] Done\r\n")
         assert_instance_of Net::IMAP::AppendUIDData, response.data.code.data
    @@ -253,17 +280,47 @@ def test_fetch_binary_and_binary_size
       test "COPYUID with parser_use_deprecated_uidplus_data = true" do
         parser = Net::IMAP::ResponseParser.new(config: {
           parser_use_deprecated_uidplus_data:      true,
    +      parser_max_deprecated_uidplus_data_size: 10_000,
         })
    +    assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do
    +      parser.parse(
    +        "A004 OK [copyUID 1 10000:20000,1 1:10001] Done\r\n"
    +      )
    +    end
    +    response = parser.parse("A004 OK [copyUID 1 100:200 1:101] Done\r\n")
    +    uidplus  = response.data.code.data
    +    assert_equal 101, uidplus.assigned_uids.size
    +    assert_equal 101, uidplus.source_uids.size
    +    parser.config.parser_max_deprecated_uidplus_data_size = 100
    +    assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do
    +      parser.parse(
    +        "A004 OK [copyUID 1 100:200 1:101] Done\r\n"
    +      )
    +    end
         response = parser.parse("A004 OK [copyUID 1 101:200 1:100] Done\r\n")
         uidplus  = response.data.code.data
         assert_instance_of Net::IMAP::UIDPlusData, uidplus
         assert_equal 100, uidplus.assigned_uids.size
         assert_equal 100, uidplus.source_uids.size
       end
     
    +  test "COPYUID with parser_use_deprecated_uidplus_data = :up_to_max_size" do
    +    parser = Net::IMAP::ResponseParser.new(config: {
    +      parser_use_deprecated_uidplus_data:      :up_to_max_size,
    +      parser_max_deprecated_uidplus_data_size: 100
    +    })
    +    response = parser.parse("A004 OK [COPYUID 1 101:200 1:100] Done\r\n")
    +    copyuid = response.data.code.data
    +    assert_instance_of Net::IMAP::UIDPlusData, copyuid
    +    response = parser.parse("A004 OK [COPYUID 1 100:200 1:101] Done\r\n")
    +    copyuid = response.data.code.data
    +    assert_instance_of Net::IMAP::CopyUIDData, copyuid
    +  end
    +
       test "COPYUID with parser_use_deprecated_uidplus_data = false" do
         parser = Net::IMAP::ResponseParser.new(config: {
           parser_use_deprecated_uidplus_data:      false,
    +      parser_max_deprecated_uidplus_data_size: 10_000_000,
         })
         response = parser.parse("A004 OK [COPYUID 1 101 1] Done\r\n")
         assert_instance_of Net::IMAP::CopyUIDData, response.data.code.data
    
cb92191b1ddc

Merge commit from fork

https://github.com/ruby/net-imapnicholas a. evansFeb 7, 2025via ghsa
6 files changed · +103 136
  • lib/net/imap/response_parser.rb+23 3 modified
    @@ -7,6 +7,8 @@ class IMAP < Protocol
     
         # Parses an \IMAP server response.
         class ResponseParser
    +      MAX_UID_SET_SIZE = 10_000
    +
           # :call-seq: Net::IMAP::ResponseParser.new -> Net::IMAP::ResponseParser
           def initialize
             @str = nil
    @@ -1379,11 +1381,29 @@ def uid_set
             case token.symbol
             when T_NUMBER then [Integer(token.value)]
             when T_ATOM
    -          token.value.split(",").flat_map {|range|
    -            range = range.split(":").map {|uniqueid| Integer(uniqueid) }
    -            range.size == 1 ? range : Range.new(range.min, range.max).to_a
    +          entries = uid_set__ranges(token.value)
    +          if (count = entries.sum(&:count)) > MAX_UID_SET_SIZE
    +            parse_error("uid-set is too large: %d > 10k", count)
    +          end
    +          entries.flat_map(&:to_a)
    +        end
    +      end
    +
    +      # returns an array of ranges
    +      def uid_set__ranges(uidset)
    +        entries = []
    +        uidset.split(",") do |entry|
    +          uids = entry.split(":", 2).map {|uid|
    +            unless uid =~ /\A[1-9][0-9]*\z/
    +              parse_error("invalid uid-set uid: %p", uid)
    +            end
    +            uid = Integer(uid)
    +            NumValidator.ensure_nz_number(uid)
    +            uid
               }
    +          entries << Range.new(*uids.minmax)
             end
    +        entries
           end
     
           def nil_atom
    
  • test/net/fixtures/cacert.pem+22 22 modified
    @@ -1,24 +1,24 @@
     -----BEGIN CERTIFICATE-----
    -MIID7TCCAtWgAwIBAgIJAIltvxrFAuSnMA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD
    -VQQGEwJKUDEQMA4GA1UECAwHU2hpbWFuZTEUMBIGA1UEBwwLTWF0ei1lIGNpdHkx
    -FzAVBgNVBAoMDlJ1YnkgQ29yZSBUZWFtMRUwEwYDVQQDDAxSdWJ5IFRlc3QgQ0Ex
    -JTAjBgkqhkiG9w0BCQEWFnNlY3VyaXR5QHJ1YnktbGFuZy5vcmcwHhcNMTkwMTAy
    -MDI1ODI4WhcNMjQwMTAxMDI1ODI4WjCBjDELMAkGA1UEBhMCSlAxEDAOBgNVBAgM
    -B1NoaW1hbmUxFDASBgNVBAcMC01hdHotZSBjaXR5MRcwFQYDVQQKDA5SdWJ5IENv
    -cmUgVGVhbTEVMBMGA1UEAwwMUnVieSBUZXN0IENBMSUwIwYJKoZIhvcNAQkBFhZz
    -ZWN1cml0eUBydWJ5LWxhbmcub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
    -CgKCAQEAznlbjRVhz1NlutHVrhcGnK8W0qug2ujKXv1njSC4U6nJF6py7I9EeehV
    -SaKePyv+I9z3K1LnfUHOtUbdwdKC77yN66A6q2aqzu5q09/NSykcZGOIF0GuItYI
    -3nvW3IqBddff2ffsyR+9pBjfb5AIPP08WowF9q4s1eGULwZc4w2B8PFhtxYANd7d
    -BvGLXFlcufv9tDtzyRi4t7eqxCRJkZQIZNZ6DHHIJrNxejOILfHLarI12yk8VK6L
    -2LG4WgGqyeePiRyd1o1MbuiAFYqAwpXNUbRKg5NaZGwBHZk8UZ+uFKt1QMBURO5R
    -WFy1c349jbWszTqFyL4Lnbg9HhAowQIDAQABo1AwTjAdBgNVHQ4EFgQU9tEiKdU9
    -I9derQyc5nWPnc34nVMwHwYDVR0jBBgwFoAU9tEiKdU9I9derQyc5nWPnc34nVMw
    -DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxj7F/u3C3fgq24N7hGRA
    -of7ClFQxGmo/IGT0AISzW3HiVYiFaikKhbO1NwD9aBpD8Zwe62sCqMh8jGV/b0+q
    -aOORnWYNy2R6r9FkASAglmdF6xn3bhgGD5ls4pCvcG9FynGnGc24g6MrjFNrBYUS
    -2iIZsg36i0IJswo/Dy6HLphCms2BMCD3DeWtfjePUiTmQHJo6HsQIKP/u4N4Fvee
    -uMBInei2M4VU74fLXbmKl1F9AEX7JDP3BKSZG19Ch5pnUo4uXM1uNTGsi07P4Y0s
    -K44+SKBC0bYEFbDK0eQWMrX3kIhkPxyIWhxdq9/NqPYjShuSEAhA6CSpmRg0pqc+
    -mA==
    +MIID+zCCAuOgAwIBAgIUGMvHl3EhtKPKcgc3NQSAYfFuC+8wDQYJKoZIhvcNAQEL
    +BQAwgYwxCzAJBgNVBAYTAkpQMRAwDgYDVQQIDAdTaGltYW5lMRQwEgYDVQQHDAtN
    +YXR6LWUgY2l0eTEXMBUGA1UECgwOUnVieSBDb3JlIFRlYW0xFTATBgNVBAMMDFJ1
    +YnkgVGVzdCBDQTElMCMGCSqGSIb3DQEJARYWc2VjdXJpdHlAcnVieS1sYW5nLm9y
    +ZzAeFw0yNDAxMDExMTQ3MjNaFw0zMzEyMjkxMTQ3MjNaMIGMMQswCQYDVQQGEwJK
    +UDEQMA4GA1UECAwHU2hpbWFuZTEUMBIGA1UEBwwLTWF0ei1lIGNpdHkxFzAVBgNV
    +BAoMDlJ1YnkgQ29yZSBUZWFtMRUwEwYDVQQDDAxSdWJ5IFRlc3QgQ0ExJTAjBgkq
    +hkiG9w0BCQEWFnNlY3VyaXR5QHJ1YnktbGFuZy5vcmcwggEiMA0GCSqGSIb3DQEB
    +AQUAA4IBDwAwggEKAoIBAQCw+egZQ6eumJKq3hfKfED4dE/tL4FI5sjqont9ABVI
    ++1GSqyi1bFBgsRjM0THllIdMbKmJtWwnKW8J+5OgNN8y6Xxv8JmM/Y5vQt2lis0f
    +qXmG8UTz0VTWdlAXXmhUs6lSADvAaIe4RVrCsZ97L3ZQTryY7JRVcbB4khUN3Gp0
    +yg+801SXzoFTTa+UGIRLE66jH51aa5VXu99hnv1OiH8tQrjdi8mH6uG/icq4XuIe
    +NWMF32wHqIOOPvQcWV3M5D2vxJEj702Ku6k9OQXkAo17qRSEonWW4HtLbtmS8He1
    +JNPc/n3dVUm+fM6NoDXPoLP7j55G9zKyqGtGAWXAj1MTAgMBAAGjUzBRMB0GA1Ud
    +DgQWBBSJGVleDvFp9cu9R+E0/OKYzGkwkTAfBgNVHSMEGDAWgBSJGVleDvFp9cu9
    +R+E0/OKYzGkwkTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBl
    +8GLB8skAWlkSw/FwbUmEV3zyqu+p7PNP5YIYoZs0D74e7yVulGQ6PKMZH5hrZmHo
    +orFSQU+VUUirG8nDGj7Rzce8WeWBxsaDGC8CE2dq6nC6LuUwtbdMnBrH0LRWAz48
    +jGFF3jHtVz8VsGfoZTZCjukWqNXvU6hETT9GsfU+PZqbqcTVRPH52+XgYayKdIbD
    +r97RM4X3+aXBHcUW0b76eyyi65RR/Xtvn8ioZt2AdX7T2tZzJyXJN3Hupp77s6Ui
    +AZR35SToHCZeTZD12YBvLBdaTPLZN7O/Q/aAO9ZiJaZ7SbFOjz813B2hxXab4Fob
    +2uJX6eMWTVxYK5D4M9lm
     -----END CERTIFICATE-----
    
  • test/net/fixtures/Makefile+3 3 modified
    @@ -5,11 +5,11 @@ regen_certs:
     	make server.crt
     
     cacert.pem: server.key
    -	openssl req -new -x509 -days 1825 -key server.key -out cacert.pem -text -subj "/C=JP/ST=Shimane/L=Matz-e city/O=Ruby Core Team/CN=Ruby Test CA/emailAddress=security@ruby-lang.org"
    +	openssl req -new -x509 -days 3650 -key server.key -out cacert.pem -subj "/C=JP/ST=Shimane/L=Matz-e city/O=Ruby Core Team/CN=Ruby Test CA/emailAddress=security@ruby-lang.org"
     
     server.csr:
    -	openssl req -new -key server.key -out server.csr -text -subj "/C=JP/ST=Shimane/O=Ruby Core Team/OU=Ruby Test/CN=localhost"
    +	openssl req -new -key server.key -out server.csr -subj "/C=JP/ST=Shimane/O=Ruby Core Team/OU=Ruby Test/CN=localhost"
     
     server.crt: server.csr cacert.pem
    -	openssl x509 -days 1825 -CA cacert.pem -CAkey server.key -set_serial 00 -in server.csr -req -text -out server.crt
    +	openssl x509 -days 3650 -CA cacert.pem -CAkey server.key -set_serial 00 -in server.csr -req -out server.crt
     	rm server.csr
    
  • test/net/fixtures/server.crt+19 80 modified
    @@ -1,82 +1,21 @@
    -Certificate:
    -    Data:
    -        Version: 3 (0x2)
    -        Serial Number: 2 (0x2)
    -    Signature Algorithm: sha256WithRSAEncryption
    -        Issuer: C=JP, ST=Shimane, L=Matz-e city, O=Ruby Core Team, CN=Ruby Test CA/emailAddress=security@ruby-lang.org
    -        Validity
    -            Not Before: Jan  2 03:27:13 2019 GMT
    -            Not After : Jan  1 03:27:13 2024 GMT
    -        Subject: C=JP, ST=Shimane, O=Ruby Core Team, OU=Ruby Test, CN=localhost
    -        Subject Public Key Info:
    -            Public Key Algorithm: rsaEncryption
    -                Public-Key: (2048 bit)
    -                Modulus:
    -                    00:e8:da:9c:01:2e:2b:10:ec:49:cd:5e:07:13:07:
    -                    9c:70:9e:c6:74:bc:13:c2:e1:6f:c6:82:fd:e3:48:
    -                    e0:2c:a5:68:c7:9e:42:de:60:54:65:e6:6a:14:57:
    -                    7a:30:d0:cc:b5:b6:d9:c3:d2:df:c9:25:97:54:67:
    -                    cf:f6:be:5e:cb:8b:ee:03:c5:e1:e2:f9:e7:f7:d1:
    -                    0c:47:f0:b8:da:33:5a:ad:41:ad:e7:b5:a2:7b:b7:
    -                    bf:30:da:60:f8:e3:54:a2:bc:3a:fd:1b:74:d9:dc:
    -                    74:42:e9:29:be:df:ac:b4:4f:eb:32:f4:06:f1:e1:
    -                    8c:4b:a8:8b:fb:29:e7:b1:bf:1d:01:ee:73:0f:f9:
    -                    40:dc:d5:15:79:d9:c6:73:d0:c0:dd:cb:e4:da:19:
    -                    47:80:c6:14:04:72:fd:9a:7c:8f:11:82:76:49:04:
    -                    79:cc:f2:5c:31:22:95:13:3e:5d:40:a6:4d:e0:a3:
    -                    02:26:7d:52:3b:bb:ed:65:a1:0f:ed:6b:b0:3c:d4:
    -                    de:61:15:5e:d3:dd:68:09:9f:4a:57:a5:c2:a9:6d:
    -                    86:92:c5:f4:a4:d4:b7:13:3b:52:63:24:05:e2:cc:
    -                    e3:8a:3c:d4:35:34:2b:10:bb:58:72:e7:e1:8d:1d:
    -                    74:8c:61:16:20:3d:d0:1c:4e:8f:6e:fd:fe:64:10:
    -                    4f:41
    -                Exponent: 65537 (0x10001)
    -        X509v3 extensions:
    -            X509v3 Basic Constraints: 
    -                CA:FALSE
    -            Netscape Comment: 
    -                OpenSSL Generated Certificate
    -            X509v3 Subject Key Identifier: 
    -                ED:28:C2:7E:AB:4B:C8:E8:FE:55:6D:66:95:31:1C:2D:60:F9:02:36
    -            X509v3 Authority Key Identifier: 
    -                keyid:F6:D1:22:29:D5:3D:23:D7:5E:AD:0C:9C:E6:75:8F:9D:CD:F8:9D:53
    -
    -    Signature Algorithm: sha256WithRSAEncryption
    -         1d:b8:c5:8b:72:41:20:65:ad:27:6f:15:63:06:26:12:8d:9c:
    -         ad:ca:f4:db:97:b4:90:cb:ff:35:94:bb:2a:a7:a1:ab:1e:35:
    -         2d:a5:3f:c9:24:b0:1a:58:89:75:3e:81:0a:2c:4f:98:f9:51:
    -         fb:c0:a3:09:d0:0a:9b:e7:a2:b7:c3:60:40:c8:f4:6d:b2:6a:
    -         56:12:17:4c:00:24:31:df:9c:60:ae:b1:68:54:a9:e6:b5:4a:
    -         04:e6:92:05:86:d9:5a:dc:96:30:a5:58:de:14:99:0f:e5:15:
    -         89:3e:9b:eb:80:e3:bd:83:c3:ea:33:35:4b:3e:2f:d3:0d:64:
    -         93:67:7f:8d:f5:3f:0c:27:bc:37:5a:cc:d6:47:16:af:5a:62:
    -         d2:da:51:f8:74:06:6b:24:ad:28:68:08:98:37:7d:ed:0e:ab:
    -         1e:82:61:05:d0:ba:75:a0:ab:21:b0:9a:fd:2b:54:86:1d:0d:
    -         1f:c2:d4:77:1f:72:26:5e:ad:8a:9f:09:36:6d:44:be:74:c2:
    -         5a:3e:ff:5c:9d:75:d6:38:7b:c5:39:f9:44:6e:a1:d1:8e:ff:
    -         63:db:c4:bb:c6:91:92:ca:5c:60:9b:1d:eb:0a:de:08:ee:bf:
    -         da:76:03:65:62:29:8b:f8:7f:c7:86:73:1e:f6:1f:2d:89:69:
    -         fd:be:bd:6e
     -----BEGIN CERTIFICATE-----
    -MIID4zCCAsugAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCSlAx
    -EDAOBgNVBAgMB1NoaW1hbmUxFDASBgNVBAcMC01hdHotZSBjaXR5MRcwFQYDVQQK
    -DA5SdWJ5IENvcmUgVGVhbTEVMBMGA1UEAwwMUnVieSBUZXN0IENBMSUwIwYJKoZI
    -hvcNAQkBFhZzZWN1cml0eUBydWJ5LWxhbmcub3JnMB4XDTE5MDEwMjAzMjcxM1oX
    -DTI0MDEwMTAzMjcxM1owYDELMAkGA1UEBhMCSlAxEDAOBgNVBAgMB1NoaW1hbmUx
    -FzAVBgNVBAoMDlJ1YnkgQ29yZSBUZWFtMRIwEAYDVQQLDAlSdWJ5IFRlc3QxEjAQ
    -BgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
    -AOjanAEuKxDsSc1eBxMHnHCexnS8E8Lhb8aC/eNI4CylaMeeQt5gVGXmahRXejDQ
    -zLW22cPS38kll1Rnz/a+XsuL7gPF4eL55/fRDEfwuNozWq1Bree1onu3vzDaYPjj
    -VKK8Ov0bdNncdELpKb7frLRP6zL0BvHhjEuoi/sp57G/HQHucw/5QNzVFXnZxnPQ
    -wN3L5NoZR4DGFARy/Zp8jxGCdkkEeczyXDEilRM+XUCmTeCjAiZ9Uju77WWhD+1r
    -sDzU3mEVXtPdaAmfSlelwqlthpLF9KTUtxM7UmMkBeLM44o81DU0KxC7WHLn4Y0d
    -dIxhFiA90BxOj279/mQQT0ECAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhC
    -AQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFO0o
    -wn6rS8jo/lVtZpUxHC1g+QI2MB8GA1UdIwQYMBaAFPbRIinVPSPXXq0MnOZ1j53N
    -+J1TMA0GCSqGSIb3DQEBCwUAA4IBAQAduMWLckEgZa0nbxVjBiYSjZytyvTbl7SQ
    -y/81lLsqp6GrHjUtpT/JJLAaWIl1PoEKLE+Y+VH7wKMJ0Aqb56K3w2BAyPRtsmpW
    -EhdMACQx35xgrrFoVKnmtUoE5pIFhtla3JYwpVjeFJkP5RWJPpvrgOO9g8PqMzVL
    -Pi/TDWSTZ3+N9T8MJ7w3WszWRxavWmLS2lH4dAZrJK0oaAiYN33tDqsegmEF0Lp1
    -oKshsJr9K1SGHQ0fwtR3H3ImXq2Knwk2bUS+dMJaPv9cnXXWOHvFOflEbqHRjv9j
    -28S7xpGSylxgmx3rCt4I7r/adgNlYimL+H/HhnMe9h8tiWn9vr1u
    +MIIDYTCCAkkCAQAwDQYJKoZIhvcNAQELBQAwgYwxCzAJBgNVBAYTAkpQMRAwDgYD
    +VQQIDAdTaGltYW5lMRQwEgYDVQQHDAtNYXR6LWUgY2l0eTEXMBUGA1UECgwOUnVi
    +eSBDb3JlIFRlYW0xFTATBgNVBAMMDFJ1YnkgVGVzdCBDQTElMCMGCSqGSIb3DQEJ
    +ARYWc2VjdXJpdHlAcnVieS1sYW5nLm9yZzAeFw0yNDAxMDExMTQ3MjNaFw0zMzEy
    +MjkxMTQ3MjNaMGAxCzAJBgNVBAYTAkpQMRAwDgYDVQQIDAdTaGltYW5lMRcwFQYD
    +VQQKDA5SdWJ5IENvcmUgVGVhbTESMBAGA1UECwwJUnVieSBUZXN0MRIwEAYDVQQD
    +DAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCw+egZ
    +Q6eumJKq3hfKfED4dE/tL4FI5sjqont9ABVI+1GSqyi1bFBgsRjM0THllIdMbKmJ
    +tWwnKW8J+5OgNN8y6Xxv8JmM/Y5vQt2lis0fqXmG8UTz0VTWdlAXXmhUs6lSADvA
    +aIe4RVrCsZ97L3ZQTryY7JRVcbB4khUN3Gp0yg+801SXzoFTTa+UGIRLE66jH51a
    +a5VXu99hnv1OiH8tQrjdi8mH6uG/icq4XuIeNWMF32wHqIOOPvQcWV3M5D2vxJEj
    +702Ku6k9OQXkAo17qRSEonWW4HtLbtmS8He1JNPc/n3dVUm+fM6NoDXPoLP7j55G
    +9zKyqGtGAWXAj1MTAgMBAAEwDQYJKoZIhvcNAQELBQADggEBACtGNdj5TEtnJBYp
    +M+LhBeU3oNteldfycEm993gJp6ghWZFg23oX8fVmyEeJr/3Ca9bAgDqg0t9a0npN
    +oWKEY6wVKqcHgu3gSvThF5c9KhGbeDDmlTSVVNQmXWX0K2d4lS2cwZHH8mCm2mrY
    +PDqlEkSc7k4qSiqigdS8i80Yk+lDXWsm8CjsiC93qaRM7DnS0WPQR0c16S95oM6G
    +VklFKUSDAuFjw9aVWA/nahOucjn0w5fVW6lyIlkBslC1ChlaDgJmvhz+Ol3iMsE0
    +kAmFNu2KKPVrpMWaBID49QwQTDyhetNLaVVFM88iUdA9JDoVMEuP1mm39JqyzHTu
    +uBrdP4Q=
     -----END CERTIFICATE-----
    
  • test/net/fixtures/server.key+27 28 modified
    @@ -1,28 +1,27 @@
    ------BEGIN PRIVATE KEY-----
    -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDo2pwBLisQ7EnN
    -XgcTB5xwnsZ0vBPC4W/Ggv3jSOAspWjHnkLeYFRl5moUV3ow0My1ttnD0t/JJZdU
    -Z8/2vl7Li+4DxeHi+ef30QxH8LjaM1qtQa3ntaJ7t78w2mD441SivDr9G3TZ3HRC
    -6Sm+36y0T+sy9Abx4YxLqIv7Keexvx0B7nMP+UDc1RV52cZz0MDdy+TaGUeAxhQE
    -cv2afI8RgnZJBHnM8lwxIpUTPl1Apk3gowImfVI7u+1loQ/ta7A81N5hFV7T3WgJ
    -n0pXpcKpbYaSxfSk1LcTO1JjJAXizOOKPNQ1NCsQu1hy5+GNHXSMYRYgPdAcTo9u
    -/f5kEE9BAgMBAAECggEBAOHkwhc7DLh8IhTDNSW26oMu5OP2WU1jmiYAigDmf+OQ
    -DBgrZj+JQBci8qINQxL8XLukSZn5hvQCLc7Kbyu1/wyEEUFDxSGGwwzclodr9kho
    -LX2LDASPZrOSzD2+fPi2wTKmXKuS6Uc44OjQfZkYMNkz9r4Vkm8xGgOD3VipjIYX
    -QXlhhdqkXZcNABsihCV52GKkDFSVm8jv95YJc5xhoYCy/3a4/qPdF0aT2R7oYUej
    -hKrxVDskyooe8Zg/JTydZNV5GQEDmW01/K3r6XGT26oPi1AqMU1gtv/jkW56CRQQ
    -1got8smnqM+AV7Slf9R6DauIPdQJ2S8wsr/o8ISBsOECgYEA9YrqEP2gAYSGFXRt
    -liw0WI2Ant8BqXS6yvq1jLo/qWhLw/ph4Di73OQ2mpycVTpgfGr2wFPQR1XJ+0Fd
    -U+Ir/C3Q7FK4VIGHK7B0zNvZr5tEjlFfeRezo2JMVw5YWeSagIFcSwK+KqCTH9qc
    -pw/Eb8nB/4XNcpTZu7Fg0Wc+ooUCgYEA8sVaicn1Wxkpb45a4qfrA6wOr5xdJ4cC
    -A5qs7vjX2OdPIQOmoQhdI7bCWFXZzF33wA4YCws6j5wRaySLIJqdms8Gl9QnODy1
    -ZlA5gwKToBC/jqPmWAXSKb8EH7cHilaxU9OKnQ7CfwlGLHqjMtjrhR7KHlt3CVRs
    -oRmvsjZVXI0CgYAmPedslAO6mMhFSSfULrhMXmV82OCqYrrA6EEkVNGbcdnzAOkD
    -gfKIWabDd8bFY10po4Mguy0CHzNhBXIioWQWV5BlbhC1YKMLw+S9DzSdLAKGY9gJ
    -xQ4+UQ3wtRQ/k+IYR413RUsW2oFvgZ3KSyNeAb9MK6uuv84VdG/OzVSs/QKBgQDn
    -kap//l2EbObiWyaERunckdVcW0lcN+KK75J/TGwPoOwQsLvTpPe65kxRGGrtDsEQ
    -uCDk/+v3KkZPLgdrrTAih9FhJ+PVN8tMcb+6IM4SA4fFFr/UPJEwct0LJ3oQ0grJ
    -y+HPWFHb/Uurh7t99/4H98uR02sjQh1wOeEmm78mzQKBgQDm+LzGH0se6CXQ6cdZ
    -g1JRZeXkDEsrW3hfAsW62xJQmXcWxBoblP9OamMY+A06rM5og3JbDk5Zm6JsOaA8
    -wS2gw4ilp46jors4eQey8ux7kB9LzdBoDBBElnsbjLO8oBNZlVcYXg+6BOl/CUi7
    -2whRF0FEjKA8ehrNhAq+VFfFNw==
    ------END PRIVATE KEY-----
    +-----BEGIN RSA PRIVATE KEY-----
    +MIIEowIBAAKCAQEAsPnoGUOnrpiSqt4XynxA+HRP7S+BSObI6qJ7fQAVSPtRkqso
    +tWxQYLEYzNEx5ZSHTGypibVsJylvCfuToDTfMul8b/CZjP2Ob0LdpYrNH6l5hvFE
    +89FU1nZQF15oVLOpUgA7wGiHuEVawrGfey92UE68mOyUVXGweJIVDdxqdMoPvNNU
    +l86BU02vlBiESxOuox+dWmuVV7vfYZ79Toh/LUK43YvJh+rhv4nKuF7iHjVjBd9s
    +B6iDjj70HFldzOQ9r8SRI+9NirupPTkF5AKNe6kUhKJ1luB7S27ZkvB3tSTT3P59
    +3VVJvnzOjaA1z6Cz+4+eRvcysqhrRgFlwI9TEwIDAQABAoIBAEEYiyDP29vCzx/+
    +dS3LqnI5BjUuJhXUnc6AWX/PCgVAO+8A+gZRgvct7PtZb0sM6P9ZcLrweomlGezI
    +FrL0/6xQaa8bBr/ve/a8155OgcjFo6fZEw3Dz7ra5fbSiPmu4/b/kvrg+Br1l77J
    +aun6uUAs1f5B9wW+vbR7tzbT/mxaUeDiBzKpe15GwcvbJtdIVMa2YErtRjc1/5B2
    +BGVXyvlJv0SIlcIEMsHgnAFOp1ZgQ08aDzvilLq8XVMOahAhP1O2A3X8hKdXPyrx
    +IVWE9bS9ptTo+eF6eNl+d7htpKGEZHUxinoQpWEBTv+iOoHsVunkEJ3vjLP3lyI/
    +fY0NQ1ECgYEA3RBXAjgvIys2gfU3keImF8e/TprLge1I2vbWmV2j6rZCg5r/AS0u
    +pii5CvJ5/T5vfJPNgPBy8B/yRDs+6PJO1GmnlhOkG9JAIPkv0RBZvR0PMBtbp6nT
    +Y3yo1lwamBVBfY6rc0sLTzosZh2aGoLzrHNMQFMGaauORzBFpY5lU50CgYEAzPHl
    +u5DI6Xgep1vr8QvCUuEesCOgJg8Yh1UqVoY/SmQh6MYAv1I9bLGwrb3WW/7kqIoD
    +fj0aQV5buVZI2loMomtU9KY5SFIsPV+JuUpy7/+VE01ZQM5FdY8wiYCQiVZYju9X
    +Wz5LxMNoz+gT7pwlLCsC4N+R8aoBk404aF1gum8CgYAJ7VTq7Zj4TFV7Soa/T1eE
    +k9y8a+kdoYk3BASpCHJ29M5R2KEA7YV9wrBklHTz8VzSTFTbKHEQ5W5csAhoL5Fo
    +qoHzFFi3Qx7MHESQb9qHyolHEMNx6QdsHUn7rlEnaTTyrXh3ifQtD6C0yTmFXUIS
    +CW9wKApOrnyKJ9nI0HcuZQKBgQCMtoV6e9VGX4AEfpuHvAAnMYQFgeBiYTkBKltQ
    +XwozhH63uMMomUmtSG87Sz1TmrXadjAhy8gsG6I0pWaN7QgBuFnzQ/HOkwTm+qKw
    +AsrZt4zeXNwsH7QXHEJCFnCmqw9QzEoZTrNtHJHpNboBuVnYcoueZEJrP8OnUG3r
    +UjmopwKBgAqB2KYYMUqAOvYcBnEfLDmyZv9BTVNHbR2lKkMYqv5LlvDaBxVfilE0
    +2riO4p6BaAdvzXjKeRrGNEKoHNBpOSfYCOM16NjL8hIZB1CaV3WbT5oY+jp7Mzd5
    +7d56RZOE+ERK2uz/7JX9VSsM/LbH9pJibd4e8mikDS9ntciqOH/3
    +-----END RSA PRIVATE KEY-----
    
  • test/net/imap/test_imap_response_parser.rb+9 0 modified
    @@ -438,4 +438,13 @@ def test_uidplus_copyuid__uid_mapping
         )
       end
     
    +  def test_uidplus_copyuid__too_large
    +    parser = Net::IMAP::ResponseParser.new
    +    assert_raise Net::IMAP::ResponseParseError, /uid-set is too large/ do
    +      parser.parse(
    +        "A004 OK [copyUID 1 10000:20000,1 1:10001] Done\r\n"
    +      )
    +    end
    +  end
    +
     end
    
70e3ddd071a9

Merge commit from fork

https://github.com/ruby/net-imapnicholas a. evansFeb 7, 2025via ghsa
3 files changed · +108 5
  • lib/net/imap/config.rb+41 2 modified
    @@ -291,6 +291,12 @@ def self.[](config)
           # CopyUIDData for +COPYUID+ response codes, and UIDPlusData or
           # AppendUIDData for +APPENDUID+ response codes.
           #
    +      # UIDPlusData stores its data in arrays of numbers, which is vulnerable to
    +      # a memory exhaustion denial of service attack from an untrusted or
    +      # compromised server.  Set this option to +false+ to completely block this
    +      # vulnerability.  Otherwise, parser_max_deprecated_uidplus_data_size
    +      # mitigates this vulnerability.
    +      #
           # AppendUIDData and CopyUIDData are _mostly_ backward-compatible with
           # UIDPlusData.  Most applications should be able to upgrade with little
           # or no changes.
    @@ -307,12 +313,41 @@ def self.[](config)
           # [+true+ <em>(original default)</em>]
           #    ResponseParser only uses UIDPlusData.
           #
    +      # [+:up_to_max_size+ <em>(default since +v0.5.6+)</em>]
    +      #    ResponseParser uses UIDPlusData when the +uid-set+ size is below
    +      #    parser_max_deprecated_uidplus_data_size.  Above that size,
    +      #    ResponseParser uses AppendUIDData or CopyUIDData.
    +      #
           # [+false+ <em>(planned default for +v0.6+)</em>]
           #    ResponseParser _only_ uses AppendUIDData and CopyUIDData.
           attr_accessor :parser_use_deprecated_uidplus_data, type: [
    -        true, false
    +        true, :up_to_max_size, false
           ]
     
    +      # The maximum +uid-set+ size that ResponseParser will parse into
    +      # deprecated UIDPlusData.  This limit only applies when
    +      # parser_use_deprecated_uidplus_data is not +false+.
    +      #
    +      # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
    +      #
    +      # <em>Support for limiting UIDPlusData to a maximum size was added in
    +      # +v0.3.8+, +v0.4.19+, and +v0.5.6+.</em>
    +      #
    +      # <em>UIDPlusData will be removed in +v0.6+.</em>
    +      #
    +      # ==== Versioned Defaults
    +      #
    +      # Because this limit guards against a remote server causing catastrophic
    +      # memory exhaustion, the versioned default (used by #load_defaults) also
    +      # applies to versions without the feature.
    +      #
    +      # * +0.3+ and prior: <tt>10,000</tt>
    +      # * +0.4+: <tt>1,000</tt>
    +      # * +0.5+: <tt>100</tt>
    +      # * +0.6+: <tt>0</tt>
    +      #
    +      attr_accessor :parser_max_deprecated_uidplus_data_size, type: Integer
    +
           # Creates a new config object and initialize its attribute with +attrs+.
           #
           # If +parent+ is not given, the global config is used by default.
    @@ -393,7 +428,8 @@ def defaults_hash
             sasl_ir: true,
             enforce_logindisabled: true,
             responses_without_block: :warn,
    -        parser_use_deprecated_uidplus_data: true,
    +        parser_use_deprecated_uidplus_data: :up_to_max_size,
    +        parser_max_deprecated_uidplus_data_size: 100,
           ).freeze
     
           @global = default.new
    @@ -406,6 +442,7 @@ def defaults_hash
             responses_without_block: :silence_deprecation_warning,
             enforce_logindisabled: false,
             parser_use_deprecated_uidplus_data: true,
    +        parser_max_deprecated_uidplus_data_size: 10_000,
           ).freeze
           version_defaults[0.0] = Config[0]
           version_defaults[0.1] = Config[0]
    @@ -414,13 +451,15 @@ def defaults_hash
     
           version_defaults[0.4] = Config[0.3].dup.update(
             sasl_ir: true,
    +        parser_max_deprecated_uidplus_data_size: 1000,
           ).freeze
     
           version_defaults[0.5] = Config[:current]
     
           version_defaults[0.6] = Config[0.5].dup.update(
             responses_without_block: :frozen_dup,
             parser_use_deprecated_uidplus_data: false,
    +        parser_max_deprecated_uidplus_data_size: 0,
           ).freeze
           version_defaults[:next] = Config[0.6]
           version_defaults[:future] = Config[:next]
    
  • lib/net/imap/response_parser.rb+10 3 modified
    @@ -2023,9 +2023,16 @@ def CopyUID(...)   DeprecatedUIDPlus(...) || CopyUIDData.new(...)   end
           # TODO: remove this code in the v0.6.0 release
           def DeprecatedUIDPlus(validity, src_uids = nil, dst_uids)
             return unless config.parser_use_deprecated_uidplus_data
    -        src_uids &&= src_uids.each_ordered_number.to_a
    -        dst_uids   = dst_uids.each_ordered_number.to_a
    -        UIDPlusData.new(validity, src_uids, dst_uids)
    +        compact_uid_sets = [src_uids, dst_uids].compact
    +        count = compact_uid_sets.map { _1.count_with_duplicates }.max
    +        max   = config.parser_max_deprecated_uidplus_data_size
    +        if count <= max
    +          src_uids &&= src_uids.each_ordered_number.to_a
    +          dst_uids   = dst_uids.each_ordered_number.to_a
    +          UIDPlusData.new(validity, src_uids, dst_uids)
    +        elsif config.parser_use_deprecated_uidplus_data != :up_to_max_size
    +          parse_error("uid-set is too large: %d > %d", count, max)
    +        end
           end
     
           ADDRESS_REGEXP = /\G
    
  • test/net/imap/test_imap_response_parser.rb+57 0 modified
    @@ -214,16 +214,43 @@ def test_fetch_binary_and_binary_size
       test "APPENDUID with parser_use_deprecated_uidplus_data = true" do
         parser = Net::IMAP::ResponseParser.new(config: {
           parser_use_deprecated_uidplus_data:      true,
    +      parser_max_deprecated_uidplus_data_size: 10_000,
         })
    +    assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do
    +      parser.parse(
    +        "A004 OK [APPENDUID 1 10000:20000,1] Done\r\n"
    +      )
    +    end
    +    response = parser.parse("A004 OK [APPENDUID 1 100:200] Done\r\n")
    +    uidplus  = response.data.code.data
    +    assert_equal 101, uidplus.assigned_uids.size
    +    parser.config.parser_max_deprecated_uidplus_data_size = 100
    +    assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do
    +      parser.parse(
    +        "A004 OK [APPENDUID 1 100:200] Done\r\n"
    +      )
    +    end
         response = parser.parse("A004 OK [APPENDUID 1 101:200] Done\r\n")
         uidplus  = response.data.code.data
         assert_instance_of Net::IMAP::UIDPlusData, uidplus
         assert_equal 100, uidplus.assigned_uids.size
       end
     
    +  test "APPENDUID with parser_use_deprecated_uidplus_data = :up_to_max_size" do
    +    parser = Net::IMAP::ResponseParser.new(config: {
    +      parser_use_deprecated_uidplus_data:      :up_to_max_size,
    +      parser_max_deprecated_uidplus_data_size: 100
    +    })
    +    response = parser.parse("A004 OK [APPENDUID 1 101:200] Done\r\n")
    +    assert_instance_of Net::IMAP::UIDPlusData, response.data.code.data
    +    response = parser.parse("A004 OK [APPENDUID 1 100:200] Done\r\n")
    +    assert_instance_of Net::IMAP::AppendUIDData, response.data.code.data
    +  end
    +
       test "APPENDUID with parser_use_deprecated_uidplus_data = false" do
         parser = Net::IMAP::ResponseParser.new(config: {
           parser_use_deprecated_uidplus_data:      false,
    +      parser_max_deprecated_uidplus_data_size: 10_000_000,
         })
         response = parser.parse("A004 OK [APPENDUID 1 10] Done\r\n")
         assert_instance_of Net::IMAP::AppendUIDData, response.data.code.data
    @@ -262,17 +289,47 @@ def test_fetch_binary_and_binary_size
       test "COPYUID with parser_use_deprecated_uidplus_data = true" do
         parser = Net::IMAP::ResponseParser.new(config: {
           parser_use_deprecated_uidplus_data:      true,
    +      parser_max_deprecated_uidplus_data_size: 10_000,
         })
    +    assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do
    +      parser.parse(
    +        "A004 OK [copyUID 1 10000:20000,1 1:10001] Done\r\n"
    +      )
    +    end
    +    response = parser.parse("A004 OK [copyUID 1 100:200 1:101] Done\r\n")
    +    uidplus  = response.data.code.data
    +    assert_equal 101, uidplus.assigned_uids.size
    +    assert_equal 101, uidplus.source_uids.size
    +    parser.config.parser_max_deprecated_uidplus_data_size = 100
    +    assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do
    +      parser.parse(
    +        "A004 OK [copyUID 1 100:200 1:101] Done\r\n"
    +      )
    +    end
         response = parser.parse("A004 OK [copyUID 1 101:200 1:100] Done\r\n")
         uidplus  = response.data.code.data
         assert_instance_of Net::IMAP::UIDPlusData, uidplus
         assert_equal 100, uidplus.assigned_uids.size
         assert_equal 100, uidplus.source_uids.size
       end
     
    +  test "COPYUID with parser_use_deprecated_uidplus_data = :up_to_max_size" do
    +    parser = Net::IMAP::ResponseParser.new(config: {
    +      parser_use_deprecated_uidplus_data:      :up_to_max_size,
    +      parser_max_deprecated_uidplus_data_size: 100
    +    })
    +    response = parser.parse("A004 OK [COPYUID 1 101:200 1:100] Done\r\n")
    +    copyuid = response.data.code.data
    +    assert_instance_of Net::IMAP::UIDPlusData, copyuid
    +    response = parser.parse("A004 OK [COPYUID 1 100:200 1:101] Done\r\n")
    +    copyuid = response.data.code.data
    +    assert_instance_of Net::IMAP::CopyUIDData, copyuid
    +  end
    +
       test "COPYUID with parser_use_deprecated_uidplus_data = false" do
         parser = Net::IMAP::ResponseParser.new(config: {
           parser_use_deprecated_uidplus_data:      false,
    +      parser_max_deprecated_uidplus_data_size: 10_000_000,
         })
         response = parser.parse("A004 OK [COPYUID 1 101 1] Done\r\n")
         assert_instance_of Net::IMAP::CopyUIDData, response.data.code.data
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

10

News mentions

0

No linked articles in our index yet.