Skip to content

Commit 44593ed

Browse files
jasnowpostmodern
andauthored
GHSA SYNC: 1 brand new advisory (#848)
--------- Co-authored-by: Postmodern <[email protected]>
1 parent b32baf6 commit 44593ed

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed

gems/net-imap/CVE-2025-25186.yml

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
---
2+
gem: net-imap
3+
cve: 2025-25186
4+
ghsa: 7fc5-f82f-cx69
5+
url: https://github.com/ruby/net-imap/security/advisories/GHSA-7fc5-f82f-cx69
6+
title: Possible DoS by memory exhaustion in net-imap
7+
date: 2025-02-10
8+
description: |
9+
### Summary
10+
11+
There is a possibility for denial of service by memory exhaustion in
12+
`net-imap`'s response parser. At any time while the client is
13+
connected, a malicious server can send can send highly compressed
14+
`uid-set` data which is automatically read by the client's receiver
15+
thread. The response parser uses `Range#to_a` to convert the
16+
`uid-set` data into arrays of integers, with no limitation on the
17+
expanded size of the ranges.
18+
19+
### Details
20+
21+
IMAP's `uid-set` and `sequence-set` formats can compress ranges of
22+
numbers, for example: `"1,2,3,4,5"` and `"1:5"` both represent the
23+
same set. When `Net::IMAP::ResponseParser` receives `APPENDUID` or
24+
`COPYUID` response codes, it expands each `uid-set` into an array of
25+
integers. On a 64 bit system, these arrays will expand to 8 bytes
26+
for each number in the set. A malicious IMAP server may send
27+
specially crafted `APPENDUID` or `COPYUID` responses with very large
28+
`uid-set` ranges.
29+
30+
The `Net::IMAP` client parses each server response in a separate
31+
thread, as soon as each responses is received from the server.
32+
This attack works even when the client does not handle the
33+
`APPENDUID` or `COPYUID` responses.
34+
35+
Malicious inputs:
36+
37+
```ruby
38+
# 40 bytes expands to ~1.6GB:
39+
"* OK [COPYUID 1 1:99999999 1:99999999]\r\n"
40+
41+
# Worst *valid* input scenario (using uint32 max),
42+
# 44 bytes expands to 64GiB:
43+
"* OK [COPYUID 1 1:4294967295 1:4294967295]\r\n"
44+
45+
# Numbers must be non-zero uint32, but this isn't validated. Arrays
46+
# larger than UINT32_MAX can be created. For example, the following
47+
# would theoretically expand to almost 800 exabytes:
48+
"* OK [COPYUID 1 1:99999999999999999999 1:99999999999999999999]\r\n"
49+
```
50+
51+
Simple way to test this:
52+
```ruby
53+
require "net/imap"
54+
55+
def test(size)
56+
input = "A004 OK [COPYUID 1 1:#{size} 1:#{size}] too large?\n"
57+
parser = Net::IMAP::ResponseParser.new
58+
parser.parse input
59+
end
60+
61+
test(99_999_999)
62+
```
63+
64+
### Fixes
65+
66+
#### Preferred Fix, minor API changes
67+
68+
Upgrade to v0.4.19, v0.5.6, or higher, and configure:
69+
70+
```ruby
71+
# globally
72+
Net::IMAP.config.parser_use_deprecated_uidplus_data = false
73+
# per-client
74+
imap = Net::IMAP.new(hostname, ssl: true,
75+
parser_use_deprecated_uidplus_data: false)
76+
imap.config.parser_use_deprecated_uidplus_data = false
77+
```
78+
79+
This replaces `UIDPlusData` with `AppendUIDData` and `CopyUIDData`.
80+
These classes store their UIDs as `Net::IMAP::SequenceSet` objects
81+
(_not_ expanded into arrays of integers). Code that does not handle
82+
`APPENDUID` or `COPYUID` responses will not notice any difference.
83+
Code that does handle these responses _may_ need to be updated. See
84+
the documentation for
85+
[UIDPlusData](https://ruby.github.io/net-imap/Net/IMAP/UIDPlusData.html),
86+
[AppendUIDData](https://ruby.github.io/net-imap/Net/IMAP/AppendUIDData.html)
87+
and [CopyUIDData](https://ruby.github.io/net-imap/Net/IMAP/CopyUIDData.html).
88+
89+
For v0.3.8, this option is not available.
90+
For v0.4.19, the default value is `true`.
91+
For v0.5.6, the default value is `:up_to_max_size`.
92+
For v0.6.0, the only allowed value will be `false` _(`UIDPlusData`
93+
will be removed from v0.6)_.
94+
95+
#### Mitigation, backward compatible API
96+
97+
Upgrade to v0.3.8, v0.4.19, v0.5.6, or higher.
98+
99+
For backward compatibility, `uid-set` can still be expanded
100+
into an array, but a maximum limit will be applied.
101+
102+
Assign `config.parser_max_deprecated_uidplus_data_size` to set the
103+
maximum `UIDPlusData` UID set size. When
104+
`config.parser_use_deprecated_uidplus_data == true`, larger sets will crash.
105+
When `config.parser_use_deprecated_uidplus_data == :up_to_max_size`,
106+
larger sets will use `AppendUIDData` or `CopyUIDData`.
107+
108+
For v0.3,8, this limit is _hard-coded_ to 10,000, and larger sets
109+
will always raise `Net::IMAP::ResponseParseError`.
110+
For v0.4.19, the limit defaults to 1000.
111+
For v0.5.6, the limit defaults to 100.
112+
For v0.6.0, the limit will be ignored _(`UIDPlusData` will be
113+
removed from v0.6)_.
114+
115+
#### Please Note: unhandled responses
116+
117+
If the client does not add response handlers to prune unhandled
118+
responses, a malicious server can still eventually exhaust all
119+
120+
client memory, by repeatedly sending malicious responses. However,
121+
`net-imap` has always retained unhandled responses, and it has always
122+
been necessary for long-lived connections to prune these responses.
123+
_This is not significantly different from connecting to a trusted
124+
server with a long-lived connection._ To limit the maximum number
125+
of retained responses, a simple handler might look something like
126+
the following:
127+
128+
```ruby
129+
limit = 1000
130+
imap.add_response_handler do |resp|
131+
next unless resp.respond_to?(:name) && resp.respond_to?(:data)
132+
name = resp.name
133+
code = resp.data.code&.name if resp.data.respond_to?(:code)
134+
if Net::IMAP::VERSION > "0.4.0"
135+
imap.responses(name) { _1.slice!(0...-limit) }
136+
imap.responses(code) { _1.slice!(0...-limit) }
137+
else
138+
imap.responses(name).slice!(0...-limit)
139+
imap.responses(code).slice!(0...-limit)
140+
end
141+
end
142+
```
143+
cvss_v3: 6.5
144+
unaffected_versions:
145+
- "< 0.3.2"
146+
patched_versions:
147+
- "~> 0.3.8"
148+
- "~> 0.4.19"
149+
- ">= 0.5.6"
150+
related:
151+
url:
152+
- https://nvd.nist.gov/vuln/detail/CVE-2025-25186
153+
- https://github.com/ruby/net-imap/security/advisories/GHSA-7fc5-f82f-cx69
154+
- https://github.com/ruby/net-imap/commit/70e3ddd071a94e450b3238570af482c296380b35
155+
- https://github.com/ruby/net-imap/commit/c8c5a643739d2669f0c9a6bb9770d0c045fd74a3
156+
- https://github.com/ruby/net-imap/commit/cb92191b1ddce2d978d01b56a0883b6ecf0b1022
157+
- https://github.com/advisories/GHSA-7fc5-f82f-cx69

0 commit comments

Comments
 (0)