ghsa-j3g3-5qv5-52mj
Vulnerability from github
Summary
There is a possibility for denial of service by memory exhaustion when net-imap
reads server responses. At any time while the client is connected, a malicious server can send can send a "literal" byte count, which is automatically read by the client's receiver thread. The response reader immediately allocates memory for the number of bytes indicated by the server response.
This should not be an issue when securely connecting to trusted IMAP servers that are well-behaved. It can affect insecure connections and buggy, untrusted, or compromised servers (for example, connecting to a user supplied hostname).
Details
The IMAP protocol allows "literal" strings to be sent in responses, prefixed with their size in curly braces (e.g. {1234567890}\r\n
). When Net::IMAP
receives a response containing a literal string, it calls IO#read
with that size. When called with a size, IO#read
immediately allocates memory to buffer the entire string before processing continues. The server does not need to send any more data. There is no limit on the size of literals that will be accepted.
Fix
Upgrade
Users should upgrade to net-imap
0.5.7 or later. A configurable max_response_size
limit has been added to Net::IMAP
's response reader. The max_response_size
limit has also been backported to net-imap
0.2.5, 0.3.9, and 0.4.20.
To set a global value for max_response_size
, users must upgrade to net-imap
~> 0.4.20, or > 0.5.7.
Configuration
To avoid backward compatibility issues for secure connections to trusted well-behaved servers, the default max_response_size
for net-imap
0.5.7 is very high (512MiB), and the default max_response_size
for net-imap
~> 0.4.20, ~> 0.3.9, and 0.2.5 is nil
(unlimited).
When connecting to untrusted servers or using insecure connections, a much lower max_response_size
should be used.
```ruby
Set the global max_response_size (only ~> v0.4.20, > 0.5.7)
Net::IMAP.config.max_response_size = 256 << 10 # 256 KiB
Set when creating the connection
imap = Net::IMAP.new(hostname, ssl: true, max_response_size: 16 << 10) # 16 KiB
Set after creating the connection
imap.max_response_size = 256 << 20 # 256 KiB
flush currently waiting read, to ensure the new setting is loaded
imap.noop ```
Please Note: max_response_size
only limits the size per response. It does not prevent a flood of individual responses and it does not limit how many unhandled responses may be stored on the responses hash. Users are responsible for adding response handlers to prune excessive unhandled responses.
Compatibility with lower max_response_size
A lower max_response_size
may cause a few commands which legitimately return very large responses to raise an exception and close the connection. The max_response_size
could be temporarily set to a higher value, but paginated or limited versions of commands should be used whenever possible. For example, to fetch message bodies:
```ruby imap.max_response_size = 256 << 20 # 256 KiB imap.noop # flush currently waiting read
fetch a message in 252KiB chunks
size = imap.uid_fetch(uid, "RFC822.SIZE").first.rfc822_size limit = 252 << 10 message = ((0..size) % limit).each_with_object("") {|offset, str| str << imap.uid_fetch(uid, "BODY.PEEK[]<#{offset}.#{limit}>").first.message(offset:) }
imap.max_response_size = 16 << 20 # 16 KiB imap.noop # flush currently waiting read ```
References
- PR to introduce max_response_size: https://github.com/ruby/net-imap/pull/444
- Specific commit: 0ae8576c1 - lib/net/imap/response_reader.rb
- Backport to 0.4: https://github.com/ruby/net-imap/pull/445
- Backport to 0.3: https://github.com/ruby/net-imap/pull/446
- Backport to 0.2: https://github.com/ruby/net-imap/pull/447
{ "affected": [ { "database_specific": { "last_known_affected_version_range": "\u003c= 0.5.6" }, "package": { "ecosystem": "RubyGems", "name": "net-imap" }, "ranges": [ { "events": [ { "introduced": "0.5.0" }, { "fixed": "0.5.7" } ], "type": "ECOSYSTEM" } ] }, { "database_specific": { "last_known_affected_version_range": "\u003c= 0.4.19" }, "package": { "ecosystem": "RubyGems", "name": "net-imap" }, "ranges": [ { "events": [ { "introduced": "0.4.0" }, { "fixed": "0.4.20" } ], "type": "ECOSYSTEM" } ] }, { "database_specific": { "last_known_affected_version_range": "\u003c= 0.3.8" }, "package": { "ecosystem": "RubyGems", "name": "net-imap" }, "ranges": [ { "events": [ { "introduced": "0.3.0" }, { "fixed": "0.3.9" } ], "type": "ECOSYSTEM" } ] }, { "database_specific": { "last_known_affected_version_range": "\u003c= 0.2.4" }, "package": { "ecosystem": "RubyGems", "name": "net-imap" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "0.2.5" } ], "type": "ECOSYSTEM" } ] } ], "aliases": [ "CVE-2025-43857" ], "database_specific": { "cwe_ids": [ "CWE-400", "CWE-405", "CWE-770", "CWE-789" ], "github_reviewed": true, "github_reviewed_at": "2025-04-28T14:17:32Z", "nvd_published_at": "2025-04-28T16:15:33Z", "severity": "MODERATE" }, "details": "### Summary\n\nThere is a possibility for denial of service by memory exhaustion when `net-imap` reads server responses. At any time while the client is connected, a malicious server can send can send a \"literal\" byte count, which is automatically read by the client\u0027s receiver thread. The response reader immediately allocates memory for the number of bytes indicated by the server response.\n\nThis should not be an issue when securely connecting to trusted IMAP servers that are well-behaved. It can affect insecure connections and buggy, untrusted, or compromised servers (for example, connecting to a user supplied hostname).\n\n### Details\n\nThe IMAP protocol allows \"literal\" strings to be sent in responses, prefixed with their size in curly braces (e.g. `{1234567890}\\r\\n`). When `Net::IMAP` receives a response containing a literal string, it calls `IO#read` with that size. When called with a size, `IO#read` immediately allocates memory to buffer the entire string before processing continues. The server does not need to send any more data. There is no limit on the size of literals that will be accepted.\n\n### Fix\n#### Upgrade\nUsers should upgrade to `net-imap` 0.5.7 or later. A configurable `max_response_size` limit has been added to `Net::IMAP`\u0027s response reader. The `max_response_size` limit has also been backported to `net-imap` 0.2.5, 0.3.9, and 0.4.20.\n\nTo set a global value for `max_response_size`, users must upgrade to `net-imap` ~\u003e 0.4.20, or \u003e 0.5.7.\n\n#### Configuration\n\nTo avoid backward compatibility issues for secure connections to trusted well-behaved servers, the default `max_response_size` for `net-imap` 0.5.7 is _very high_ (512MiB), and the default `max_response_size` for `net-imap` ~\u003e 0.4.20, ~\u003e 0.3.9, and 0.2.5 is `nil` (unlimited).\n\nWhen connecting to untrusted servers or using insecure connections, a much lower `max_response_size` should be used.\n```ruby\n# Set the global max_response_size (only ~\u003e v0.4.20, \u003e 0.5.7)\nNet::IMAP.config.max_response_size = 256 \u003c\u003c 10 # 256 KiB\n\n# Set when creating the connection\nimap = Net::IMAP.new(hostname, ssl: true,\n max_response_size: 16 \u003c\u003c 10) # 16 KiB\n\n# Set after creating the connection\nimap.max_response_size = 256 \u003c\u003c 20 # 256 KiB\n# flush currently waiting read, to ensure the new setting is loaded\nimap.noop\n```\n\n_**Please Note:**_ `max_response_size` only limits the size _per response_. It does not prevent a flood of individual responses and it does not limit how many unhandled responses may be stored on the responses hash. Users are responsible for adding response handlers to prune excessive unhandled responses.\n\n#### Compatibility with lower `max_response_size`\n\nA lower `max_response_size` may cause a few commands which legitimately return very large responses to raise an exception and close the connection. The `max_response_size` could be temporarily set to a higher value, but paginated or limited versions of commands should be used whenever possible. For example, to fetch message bodies:\n\n```ruby\nimap.max_response_size = 256 \u003c\u003c 20 # 256 KiB\nimap.noop # flush currently waiting read\n\n# fetch a message in 252KiB chunks\nsize = imap.uid_fetch(uid, \"RFC822.SIZE\").first.rfc822_size\nlimit = 252 \u003c\u003c 10\nmessage = ((0..size) % limit).each_with_object(\"\") {|offset, str|\n str \u003c\u003c imap.uid_fetch(uid, \"BODY.PEEK[]\u003c#{offset}.#{limit}\u003e\").first.message(offset:)\n}\n\nimap.max_response_size = 16 \u003c\u003c 20 # 16 KiB\nimap.noop # flush currently waiting read\n```\n\n### References\n\n* PR to introduce max_response_size: https://github.com/ruby/net-imap/pull/444\n * Specific commit: [0ae8576c1 - lib/net/imap/response_reader.rb](https://github.com/ruby/net-imap/pull/444/commits/0ae8576c1a90bcd9573f81bdad4b4b824642d105#diff-53721cb4d9c3fb86b95cc8476ca2df90968ad8c481645220c607034399151462)\n* Backport to 0.4: https://github.com/ruby/net-imap/pull/445\n* Backport to 0.3: https://github.com/ruby/net-imap/pull/446\n* Backport to 0.2: https://github.com/ruby/net-imap/pull/447", "id": "GHSA-j3g3-5qv5-52mj", "modified": "2025-04-30T17:58:00Z", "published": "2025-04-28T14:17:32Z", "references": [ { "type": "WEB", "url": "https://github.com/ruby/net-imap/security/advisories/GHSA-j3g3-5qv5-52mj" }, { "type": "ADVISORY", "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-43857" }, { "type": "WEB", "url": "https://github.com/ruby/net-imap/pull/444" }, { "type": "WEB", "url": "https://github.com/ruby/net-imap/pull/444/commits/0ae8576c1a90bcd9573f81bdad4b4b824642d105#diff-53721cb4d9c3fb86b95cc8476ca2df90968ad8c481645220c607034399151462" }, { "type": "WEB", "url": "https://github.com/ruby/net-imap/pull/445" }, { "type": "WEB", "url": "https://github.com/ruby/net-imap/pull/446" }, { "type": "WEB", "url": "https://github.com/ruby/net-imap/pull/447" }, { "type": "PACKAGE", "url": "https://github.com/ruby/net-imap" }, { "type": "WEB", "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/net-imap/CVE-2025-43857.yml" } ], "schema_version": "1.4.0", "severity": [ { "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N", "type": "CVSS_V4" } ], "summary": "net-imap rubygem vulnerable to possible DoS by memory exhaustion" }
Sightings
Author | Source | Type | Date |
---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
- Confirmed: The vulnerability is confirmed from an analyst perspective.
- Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
- Patched: This vulnerability was successfully patched by the user reporting the sighting.
- Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
- Not confirmed: The user expresses doubt about the veracity of the vulnerability.
- Not patched: This vulnerability was not successfully patched by the user reporting the sighting.