Stapler Remover: Unbolting Jenkins with CVE-2018-1999047
Jan 7, 2026·6 min read
Executive Summary (TL;DR)
Jenkins uses a web framework called Stapler to handle HTTP requests. A logic flaw in how Stapler serves static resources allows an attacker to use `../` sequences to break out of the intended directory. By requesting a URL like `/plugin/git/../../secrets/master.key`, an attacker can steal the encryption keys used to protect all Jenkins secrets, turning a simple file read into a full administrative takeover.
A critical path traversal vulnerability in the Jenkins Stapler web framework allows unauthenticated attackers to read arbitrary files from the Jenkins master file system. This often leads to the exfiltration of cryptographic keys and credentials, resulting in total system compromise.
The Hook: The Butler Did It (Again)
Jenkins is the ubiquitous butler of the DevOps world. It builds your code, deploys your apps, and holds the keys to your entire infrastructure. Because it interacts with so many systems, it is a treasure trove of secrets—AWS keys, SSH credentials, Artifactory tokens. To manage this complexity, Jenkins relies on a web framework called Stapler. If Jenkins is the body, Stapler is the nervous system, mapping URLs to Java objects and handling the dispatching of requests.
Usually, when you hear about Jenkins vulnerabilities, you think of deserialization attacks or Groovy script sandboxing escapes. But CVE-2018-1999047 is different. It’s a classic, old-school vulnerability class found in a modern, complex framework: Path Traversal. It proves that no matter how many abstraction layers you build, if you mess up basic file I/O handling, you are going to have a bad time.
The vulnerability resides in how Stapler handles "static resources" for plugins. Plugins in Jenkins often need to serve images, CSS, or JavaScript files. Stapler provides a convenient mechanism to map a URL like /plugin/my-plugin/icon.png directly to a file on disk inside the plugin's archive. The problem? Stapler trusted the user's input a little too much, assuming that nobody would be rude enough to ask for ../../../../etc/passwd. Spoiler: We are exactly that rude.
The Flaw: A Failure of Canonicalization
The root cause of this vulnerability is a discrepancy between how a URL is parsed and how the file system interprets it. When Stapler receives a request for a static resource, it takes the path suffix and appends it to the plugin's base resource directory. In a secure implementation, the system would verify that the resulting file path is still contained within the intended directory before reading the file.
Stapler failed to perform this check effectively. It allowed standard directory traversal sequences (../) to be passed to the underlying file system APIs. In Java, if you create a new File(parent, "../child"), the file object actually points to the sibling of the parent. If you don't call getCanonicalPath() to resolve these .. sequences and compare the result against the allowed root, you have a traversal vulnerability.
What makes this specific instance juicy is that Jenkins plugins are stored in the JENKINS_HOME/plugins directory, which is usually right next to JENKINS_HOME/secrets and JENKINS_HOME/credentials.xml. The traversal distance is short, predictable, and devastatingly effective. The attacker doesn't need to guess where the files are; the directory structure of Jenkins is standardized.
The Code: Breaking out of the Jail
Let's look at the logic. The vulnerable code in Stapler's MetaClass handling (specifically relating to resource serving) essentially operated like this (pseudocode for clarity):
// Vulnerable Logic
public void serveResource(StaplerRequest req, StaplerResponse rsp) {
String path = req.getRestOfPath(); // e.g., "/../../config.xml"
URL resource = pluginClass.getResource(path);
if (resource != null) {
// Serve the file content
copy(resource.openStream(), rsp.getOutputStream());
}
}The getResource call in Java's standard library (and by extension the ClassLoader) can sometimes be tricked, but usually, this is about file system access layers that Stapler wraps. The actual fix introduced in Stapler involves strictly validating the path format before attempting to resolve the resource.
The patch effectively added a sanity check. Before serving the resource, the system now ensures the path does not contain .. elements that resolve outside the base directory:
// The Logic Fix
if (path.contains("..")) {
// Resolve canonical paths
File requestedFile = new File(baseDir, path);
if (!requestedFile.getCanonicalPath().startsWith(baseDir.getCanonicalPath())) {
throw new SecurityException("Path traversal attempt detected!");
}
}By comparing the canonical (absolute, resolved) path of the requested file against the canonical path of the allowed directory, the system ensures that even if .. is used, the resulting pointer must still reside inside the safe zone. Without this check, the .. simply walks up the directory tree.
The Exploit: Stealing the Keys to the Kingdom
To exploit this, an attacker needs two things: network access to the Jenkins instance (often available on port 8080) and the name of at least one installed plugin. Since plugins like git, subversion, or credentials are installed on 99% of Jenkins instances, this is a trivial requirement.
The attack vector targets the /plugin/ route. The exploit URL looks like this:
GET /plugin/credentials/../../secrets/master.key HTTP/1.1
Host: jenkins.victim.corpIf the server is vulnerable, it will ignore the fact that you aren't asking for an image inside the credentials plugin and instead serve up the binary content of the master.key file. This key is the Holy Grail of Jenkins exploitation.
But we don't stop there. Once we have master.key, we also grab hudson.util.Secret. With these two files, we can perform offline decryption of the credentials.xml file (which we can also steal using the same traversal).
The Attack Chain:
- Recon: Identify a valid plugin name (brute force or common lists).
- Exploit: Request
/plugin/[NAME]/../../secrets/master.key. - Exploit: Request
/plugin/[NAME]/../../secrets/hudson.util.Secret. - Exploit: Request
/plugin/[NAME]/../../credentials.xml. - Offline: Use a tool like
jenkins-decryptto recover cleartext passwords for SSH, AWS, and Database connections. - Pivot: Log in to the target infrastructure using the stolen credentials.
The Impact: Why This Keeps Security Engineers Up at Night
This vulnerability is technically an "Information Disclosure," but that label is woefully inadequate. It creates a direct path to Remote Code Execution (RCE) and infrastructure takeover. Jenkins is rarely a standalone island; it is the bridge between code repositories and production environments.
If an attacker decrypts the credentials stored in Jenkins, they can usually SSH into production servers, push malicious code to Git repositories, or deploy backdoored artifacts to app stores. The impact is Critical. The loss of confidentiality here immediately leads to a complete loss of integrity and availability.
Furthermore, because the request looks like a standard fetch for static resources, it can easily fly under the radar of poorly configured WAFs or logging systems that ignore "image" requests. It requires no authentication, meaning any bot scanning the internet can scrape your secrets and sell them before you even wake up.
The Mitigation: Locking the Windows
The primary fix is to upgrade Jenkins. The vulnerability was patched in Jenkins 2.154 (for the main line) and 2.138.4 (for the LTS line). These updates include the patched version of the Stapler framework that correctly canonicalizes paths.
If immediate patching is impossible (and let's be honest, in enterprise environments, it often is), you can mitigate this at the network layer. A Web Application Firewall (WAF) or a reverse proxy (like Nginx) can be configured to drop requests containing .. or %2e%2e in the URL path, specifically if they follow /plugin/.
However, be careful with regex blocking. Attackers love bypasses. They might use different encodings, such as double URL encoding (%252e%252e) or UTF-8 variations. The provided WAF rules in this report cover the most common traversal patterns and specifically watch for attempts to access sensitive Jenkins filenames.
Official Patches
Technical Appendix
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
Jenkins Jenkins Project | <= 2.153 | 2.154 |
Jenkins LTS Jenkins Project | <= 2.138.3 | 2.138.4 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| CWE Name | Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') |
| CVSS Score | 7.5 (High) |
| Attack Vector | Network |
| Attack Complexity | Low |
| Privileges Required | None |
MITRE ATT&CK Mapping
The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.