|
| 1 | +--- |
| 2 | +layout: advisory |
| 3 | +title: 'CVE-2026-42257 (net-imap): net-imap vulnerable to command Injection via "raw" |
| 4 | + arguments to multiple commands' |
| 5 | +comments: false |
| 6 | +categories: |
| 7 | +- net-imap |
| 8 | +advisory: |
| 9 | + gem: net-imap |
| 10 | + cve: 2026-42257 |
| 11 | + ghsa: hm49-wcqc-g2xg |
| 12 | + url: https://github.com/ruby/net-imap/security/advisories/GHSA-hm49-wcqc-g2xg |
| 13 | + title: net-imap vulnerable to command Injection via "raw" arguments to multiple |
| 14 | + commands |
| 15 | + date: 2026-05-04 |
| 16 | + description: |- |
| 17 | + ### Summary |
| 18 | +
|
| 19 | + Several `Net::IMAP` commands accept a raw string argument that is sent to the |
| 20 | + server without validation or escaping. If this string is derived from |
| 21 | + user-controlled input, it may contain contain `CRLF` sequences, which an |
| 22 | + attacker can use to inject arbitrary IMAP commands. |
| 23 | +
|
| 24 | + ### Details |
| 25 | +
|
| 26 | + `Net::IMAP`'s generic argument handling, used by most command arguments, |
| 27 | + interprets string arguments as an IMAP `astring`. Depending on the string |
| 28 | + contents and the connection's UTF-8 support, this encodes strings as either a |
| 29 | + `atom`, `quoted`, or `literal`. These are safe from command or argument |
| 30 | + injection. |
| 31 | +
|
| 32 | + But the following commands transform specific String arguments to |
| 33 | + `Net::IMAP::RawData`, which bypasses normal argument validation and encoding |
| 34 | + and prints the string directly to the socket: |
| 35 | +
|
| 36 | + * `#uid_search`, `#search` |
| 37 | + * when `criteria` is a String, it is sent raw |
| 38 | + * `#uid_fetch`, `#fetch` |
| 39 | + * when `attr` is a String, it is sent raw |
| 40 | + * when `attr` is an Array, each String in `attr` is sent raw |
| 41 | + * `#uid_store`, `#store` |
| 42 | + * when `attr` is a String, it is sent raw |
| 43 | + * `#setquota`: |
| 44 | + * `limit` is interpolated with `#to_s` and that string is sent raw |
| 45 | +
|
| 46 | + Because these string arguments are sent without any neutralization, they serve |
| 47 | + as a direct vector for command splitting. Any user controlled data |
| 48 | + interpolated into these strings can be used to break out of the intended |
| 49 | + command context. |
| 50 | +
|
| 51 | + Using "raw data" arguments for `#uid_store`, `#store`, and `#setquota` I both |
| 52 | + inappropriate and unnecessary. `Net::IMAP`'s generic argument handling is |
| 53 | + sufficient to safely validate and encode their arguments. Users of the |
| 54 | + library probably do not expect arguments to these commands to be sent raw and |
| 55 | + might not be wary of passing unvalidated input. |
| 56 | +
|
| 57 | + The API for search criteria and fetch attributes is intentionally low-level |
| 58 | + and "close to the wire". It allows developers to use some IMAP extensions |
| 59 | + without requiring explicit support from the library and allows developers to |
| 60 | + use complex IMAP grammar without complex argument translation. Even so, basic |
| 61 | + validation is appropriate and could neutralize command injection. |
| 62 | +
|
| 63 | + Although this was explicitly documented for search `criteria`, it was |
| 64 | + insufficiently documented for fetch `attr`. So developers may not have |
| 65 | + realized that the `attr` argument to `#fetch` and `#uid_fetch` is sent as "raw |
| 66 | + data". |
| 67 | +
|
| 68 | + ### Impact |
| 69 | +
|
| 70 | + If a developer passes an unvalidated user-controlled input for one of these |
| 71 | + method arguments, an attacker can append CRLF sequence followed by a new IMAP |
| 72 | + command (like DELETE mailbox). Although this does not _directly_ enable data |
| 73 | + exfiltration, it could be combined with other attack vectors or knowledge of |
| 74 | + the target system's attributes, e.g.: shared mail folders or the application's |
| 75 | + installed response handlers. |
| 76 | +
|
| 77 | + The SEARCH, STORE, and FETCH commands, and their UID variants are some of the |
| 78 | + most commonly used features of the library. Applications that build search |
| 79 | + queries or fetch attributes dynamically based on user input (e.g., mail |
| 80 | + clients or archival tools) may be at significant risk. |
| 81 | +
|
| 82 | + Expected use of `Net::IMAP#setquota` is much more limited: `SETQUOTA` is often |
| 83 | + only usable by users with special administrative privileges. Depending on the |
| 84 | + server, quota administration might be managed through server configuration |
| 85 | + rather than via the IMAP protocol `SETQUOTA` command. It is expected to be |
| 86 | + uncommonly used in system administration scripts or in interactive sessions, |
| 87 | + it should be completely controlled by trusted users, and should only use |
| 88 | + trusted inputs. Calling `#setquota` with untrusted user input is expected to |
| 89 | + be a very uncommon use case. Please note however this might be combined with |
| 90 | + other attacks, for example CSRF, which provide unauthorized access to trusted |
| 91 | + inputs, and may specifically target users or scripts with administrator |
| 92 | + privileges. |
| 93 | +
|
| 94 | + ### Mitigation |
| 95 | +
|
| 96 | + - Update to a patched version of `net-imap` which: |
| 97 | + - validates that `Net::IMAP::RawData` is composed of well-formed IMAP |
| 98 | + `text`, `literal`, and `literal8` values, with no unescaped `NULL`, `CR`, |
| 99 | + or `LF` bytes. |
| 100 | + - does not use `Net::IMAP::RawData` for `#store`, `#uid_store`, or |
| 101 | + `#setquota`. |
| 102 | + - Prefer to send search criteria as an array of key value pairs. Avoid |
| 103 | + sending it as an interpolated string. |
| 104 | + - If an immediate upgrade is not possible: |
| 105 | + - String inputs to search criteria and fetch attributes can be validated |
| 106 | + against command injection by checking for `\r` and `\n` characters. |
| 107 | + - Hard-coding the store `attr` argument is often appropriate. |
| 108 | + Alternatively, user controlled inputs can be restricted to a small |
| 109 | + enumerated list which is valid for the calling application. |
| 110 | + - Use `Kernel#Integer` to coerce and validate user controlled inputs to |
| 111 | + `#setquota` limit. |
| 112 | + cvss_v4: 5.8 |
| 113 | + patched_versions: |
| 114 | + - "~> 0.4.24" |
| 115 | + - "~> 0.5.14" |
| 116 | + - ">= 0.6.4" |
| 117 | + related: |
| 118 | + url: |
| 119 | + - https://github.com/ruby/net-imap/security/advisories/GHSA-hm49-wcqc-g2xg |
| 120 | + - https://github.com/ruby/net-imap/commit/0ec4fd351263e8b9a4f683713427827b7b1ad974 |
| 121 | + - https://github.com/ruby/net-imap/commit/47c72186d272441878ca73c9499f66013829ca2f |
| 122 | + - https://github.com/ruby/net-imap/commit/6bf02aef7e0b5931010c36e377f79a71636b306b |
| 123 | + - https://github.com/ruby/net-imap/commit/a4f7649c3da77dec7631f03a037a478eb4330048 |
| 124 | + - https://github.com/ruby/net-imap/commit/aec06996eb87a7e1bbcef1f9f8926e8add2b8c71 |
| 125 | + - https://github.com/ruby/net-imap/releases/tag/v0.4.24 |
| 126 | + - https://github.com/ruby/net-imap/releases/tag/v0.5.14 |
| 127 | + - https://github.com/ruby/net-imap/releases/tag/v0.6.4 |
| 128 | + - https://github.com/advisories/GHSA-hm49-wcqc-g2xg |
| 129 | +--- |
0 commit comments