CVE-2007-6612: Mongrel Directory Traversal via Double-Encoded Sequences
An examination of CVE-2007-6612, a high-profile vulnerability discovered in December 2007 in Mongrel, a once-dominant open-source web server library for Ruby applications. This flaw allowed remote attackers to bypass path validation using double-encoded sequences, potentially accessing sensitive files on the host system.
The Threat of Directory Traversal
When we build web servers, our primary responsibility is serving files securely from a specific, isolated directory. This directory — often called the document root — acts as a boundary between public web assets and the sensitive files of the host operating system. If an attacker can manipulate the file path requested by the browser to escape this boundary, they can potentially read arbitrary files on the system, such as /etc/passwd or application configuration files containing database credentials.
This attack is known as directory traversal, or path traversal. It typically involves injecting ../ (dot-dot-slash) sequences into the URL to navigate up the directory hierarchy. While most web servers recognize and block simple ../ sequences, attackers continuously search for ways to bypass these filters.
This is precisely the vulnerability described in CVE-2007-6612, found in Mongrel versions 1.1.0 through 1.1.2, and 1.0.4.
How Double-Encoding Bypassed Validation
In standard URL encoding, characters that have special meaning in a URL are replaced with a percentage sign followed by their hexadecimal equivalent. For instance, a percentage sign (%) becomes %25, and a dot (.) becomes %2e.
A standard directory traversal attempt might look like ../../../etc/passwd. A web server with basic security filters would easily spot and reject this. However, attackers realized they could encode these characters to slip past naive filters. If a filter only looked for literal ../ strings, it would miss %2e%2e/.
Web servers soon adapted by decoding the URL before performing security checks. But what happens if the attacker encodes the encoded characters? This is double-encoding.
To create a double-encoded sequence, an attacker first encodes the dot (.) as %2e. Then, they encode the percentage sign (%) in %2e as %25. The result is %252e.
In the case of Mongrel, the vulnerability in the static file serving component, DirHandler, arose because the application inadvertently performed two rounds of unescaping on the requested path.
- The initial HTTP parsing layer decoded the URL once, converting
/%252e/%252e/into/.%2e/.%2e/. - The
DirHandlercalledMongrel::HttpRequest.unescape(path_info)within the Ruby handler. This executed a second unescaping pass, converting the/.%2e/.%2e/directly into/../../, the parent directory notation.
This double unescaping flaw meant that by the time the path was evaluated by Ruby’s File.expand_path, it contained valid parent directory sequences that resolved backwards into the host operating system.
The Missing Validation Check
The root cause of this vulnerability wasn’t just the double unescaping; it was a regression in the code logic. The bug was accidentally introduced in version 1.0.4 when a critical security validation check was removed.
In earlier, secure versions of Mongrel (like 1.0.3), the server used File.expand_path to resolve the absolute path of the requested file. Crucially, it then performed a prefix check to ensure that the fully resolved absolute path string still started with the configured web document root.
When this specific prefix check was removed in 1.0.4, File.expand_path happily resolved the .. sequences, and the web server blindly served whatever file the expanded path pointed to, provided the file existed and the Ruby process had permission to read it.
The Fix and Long-Term Lessons
The vulnerability was quickly patched in Mongrel versions 1.1.3 and 1.0.5. The fix fundamentally involved restoring the missing validation check to guarantee that any file served strictly lived inside the intended directory hierarchy.
The patched code logic ensured that all paths must be forcefully expanded before any comparisons are made, preventing indirect paths from bypassing the security perimeter:
# 1. Expand the path to resolve any decoded ".." relative directory sequences
req_path = File.expand_path(File.join(@path, Mongrel::HttpRequest.unescape(path_info)))
# 2. Check that the final resolved absolute path actually begins with the
# authorized web root directory (@path).
if req_path.index(@path) == 0 and File.exist?(req_path)
# It exists and it's in the right location; proceed to serve it.
if File.directory?(req_path)
# Directory handling logic
end
end
By ensuring that the prefix of req_path is explicitly verified against the document root after full evaluation by File.expand_path(), the patched Mongrel versions made it impossible for attackers to traverse outside the directory, regardless of how many .. sequences were hidden in double-encoded HTTP requests.
The discovery and resolution of CVE-2007-6612 provide essential lessons for application security and long-term maintainability. Relying solely on input sanitization or filtering to prevent directory traversal is fundamentally flawed, as attackers will continually find new encoding schemes — like double-encoding, UTF-8 overlong encoding, or null-byte injection — to bypass these filters.
Instead, the definitive defense against path traversal relies on secure architectural patterns. We must normalize and fully resolve file paths using native operating system or language-level path expansion features, and then strictly validate that the resulting absolute path resides entirely within the intended base directory. This principle of validating the final state of the data, rather than attempting to filter out all malicious inputs, remains a cornerstone of secure file handling.
Sponsored by Durable Programming
Need help maintaining or upgrading your Ruby on Rails application? Durable Programming specializes in keeping Rails apps secure, performant, and up-to-date.
Hire Durable Programming