CVE-2019-18978
Description
An issue was discovered in the rack-cors (aka Rack CORS Middleware) gem before 1.0.4 for Ruby. It allows ../ directory traversal to access private resources because resource matching does not ensure that pathnames are in a canonical format.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2019-18978 is a directory traversal vulnerability in rack-cors before 1.0.4 allowing access to private resources via ../ sequences.
Vulnerability
Overview CVE-2019-18978 is a directory traversal vulnerability in the rack-cors gem for Ruby, versions before 1.0.4. The issue arises because the middleware's resource matching does not canonicalize pathnames before checking them against CORS rules [1]. This allows an attacker to use '../' sequences in the URL path to bypass intended resource restrictions.
Exploitation
Details The vulnerability can be exploited by sending a specially crafted HTTP request with path traversal sequences (e.g., ../) in the PATH_INFO. The rack-cors middleware would match the request against its resource configuration without first resolving the path to a canonical form [3]. An attacker does not need authentication if the targeted resource is otherwise accessible; the flaw is in the CORS enforcement logic itself.
Impact
Successful exploitation allows an attacker to read arbitrary files or access private resources that should be protected by CORS policies [1]. This can lead to information disclosure, including sensitive data stored on the server [4]. The impact is limited to resources that the web application can serve, but it expands the attack surface beyond what the CORS rules intended.
Mitigation
The vulnerability is fixed in rack-cors version 1.0.4. Users should upgrade immediately [2]. The fix involves unescaping and resolving the path using Rack::Utils.clean_path_info and Rack::Utils.unescape_path before performing resource checks [3]. Ubuntu also released a security update (USN-4571-1) for the ruby-rack-cors package [4].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
rack-corsRubyGems | < 1.0.4 | 1.0.4 |
Affected products
1Patches
1e4d4fc362a43Unescape and resolve paths before resource checks
5 files changed · +29 −10
CHANGELOG.md+4 −0 modified@@ -1,6 +1,10 @@ # Change Log All notable changes to this project will be documented in this file. +## 1.0.4 - 2019-11-13 +### Security +- Escape and resolve path before evaluating resource rules (thanks to Colby Morgan) + ## 1.0.3 - 2019-03-24 ### Changed - Don't send 'Content-Type' header with pre-flight requests
lib/rack/cors.rb+17 −9 modified@@ -64,24 +64,27 @@ def allow(&block) def call(env) env[HTTP_ORIGIN] ||= env[HTTP_X_ORIGIN] if env[HTTP_X_ORIGIN] + path = evaluate_path(env) + add_headers = nil if env[HTTP_ORIGIN] debug(env) do [ 'Incoming Headers:', " Origin: #{env[HTTP_ORIGIN]}", + " Path-Info: #{path}", " Access-Control-Request-Method: #{env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]}", " Access-Control-Request-Headers: #{env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]}" ].join("\n") end if env[REQUEST_METHOD] == OPTIONS and env[HTTP_ACCESS_CONTROL_REQUEST_METHOD] - headers = process_preflight(env) + headers = process_preflight(env, path) debug(env) do "Preflight Headers:\n" + headers.collect{|kv| " #{kv.join(': ')}"}.join("\n") end return [200, headers, []] else - add_headers = process_cors(env) + add_headers = process_cors(env, path) end else Result.miss(env, Result::MISS_NO_ORIGIN) @@ -90,7 +93,7 @@ def call(env) # This call must be done BEFORE calling the app because for some reason # env[PATH_INFO] gets changed after that and it won't match. (At least # in rails 4.1.6) - vary_resource = resource_for_path(env[PATH_INFO]) + vary_resource = resource_for_path(path) status, headers, body = @app.call env @@ -147,14 +150,20 @@ def select_logger(env) end end + def evaluate_path(env) + path = env[PATH_INFO] + path = Rack::Utils.clean_path_info(Rack::Utils.unescape_path(path)) if path + path + end + def all_resources @all_resources ||= [] end - def process_preflight(env) + def process_preflight(env, path) result = Result.preflight(env) - resource, error = match_resource(env) + resource, error = match_resource(path, env) unless resource result.miss(error) return {} @@ -163,8 +172,8 @@ def process_preflight(env) return resource.process_preflight(env, result) end - def process_cors(env) - resource, error = match_resource(env) + def process_cors(env, path) + resource, error = match_resource(path, env) if resource Result.hit(env) cors = resource.to_headers(env) @@ -185,8 +194,7 @@ def resource_for_path(path_info) nil end - def match_resource(env) - path = env[PATH_INFO] + def match_resource(path, env) origin = env[HTTP_ORIGIN] origin_matched = false
lib/rack/cors/version.rb+1 −1 modified@@ -1,5 +1,5 @@ module Rack class Cors - VERSION = "1.0.3" + VERSION = "1.0.4" end end
test/unit/cors_test.rb+6 −0 modified@@ -146,6 +146,12 @@ def load_app(name, options = {}) last_response.headers['Vary'].must_equal 'Origin, Host' end + it "decode URL and resolve paths before resource matching" do + header 'Origin', 'http://localhost:3000' + get '/public/a/..%2F..%2Fprivate/stuff' + last_response.wont_render_cors_success + end + describe 'with array of upstream Vary headers' do let(:app) { load_app('test', { proxy: true }) }
test/unit/test.ru+1 −0 modified@@ -41,6 +41,7 @@ use Rack::Cors do allow do origins '*' resource '/public' + resource '/public/*' resource '/public_without_credentials', :credentials => false end
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
9- github.com/advisories/GHSA-pf8f-w267-mq2hghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2019-18978ghsaADVISORY
- usn.ubuntu.com/4571-1/mitrevendor-advisoryx_refsource_UBUNTU
- www.debian.org/security/2021/dsa-4918ghsavendor-advisoryx_refsource_DEBIANWEB
- github.com/cyu/rack-cors/commit/e4d4fc362a4315808927011cbe5afcfe5486f17dghsax_refsource_MISCWEB
- github.com/cyu/rack-cors/compare/v1.0.3...v1.0.4ghsax_refsource_MISCWEB
- lists.debian.org/debian-lts-announce/2020/02/msg00004.htmlghsamailing-listx_refsource_MLISTWEB
- lists.debian.org/debian-lts-announce/2020/10/msg00000.htmlghsamailing-listx_refsource_MLISTWEB
- usn.ubuntu.com/4571-1ghsaWEB
News mentions
0No linked articles in our index yet.