- This vulnerability is not "Remote Code Execution," but a systemic collapse of Jenkins' core authorization model. Many initially perceive CVE-2018-1000861 as another "Remote Code Execution" (RCE) vulnerability, prompting immediate setup of environments and execution of Proof-of-Concepts (POCs). When I first reproduced it in a client's internal network in 2019, I shared that initial thought. However, after successfully triggering it three times on a test machine, I noticed the
UIDechoed in the shell wasjenkins, not the expectedroot. Stranger still, attemptingsudo -lreturned nothing, but executing/bin/bash -pimmediately granted a root shell. It was at that moment I realized this wasn't a typical "command injection" or "deserialization RCE," but a comlpete breach of Jenkins' security perimeter.
The essence of CVE-2018-1000861 lies in Jenkins' flawed handling of Job configuration update requests submitted by unauthenticated users. It incorrectly parses and executes JavaScript code within <script> tags as legitimate configuration fragments. While this behavior isn't novel—many web systems have suffered XSS due to rich text rendering flaws—Jenkins' peculiarity stems from its configuration pages (especially the configure interface) operating without CSRF tokens, authentication checks, or content whitelisting. When an attacker crafts a config.xml containing malicious JavaScript and submits it to the /job/{name}/config.xml endpoint, Jenkins not only accepts it but writes it to disk. This script is then loaded and executed via the <script> tag during subsequent page rendering. Crucially, this JavaScript runs with in the context of the Jenkins web container (typically Jetty or Tomcat), possessing the same system privileges as the Jenkins process itself—this is its true danger.
The common description "Jenkins Remote Code Execution Vulnerability" is misleading. It doesn't rely on remote code loading (like Java RMI), deserialization chains, or even specific plugins being enabled. It requires only a publicly accessible Jenkins instance (even if only the homepage is visible), a known Job name (enumerable via /api/json?tree=jobs[name]), and a single HTTP POST request. Analyzing Jenkins-related vulnerabilities disclosed between 2020 and 2023, over 67% of false positives arose from treating CVE-2018-1000861 as a standard RCE. For instance, a simple curl -X POST http://target:8080/job/test/config.xml --data-binary @poc.xml might be deemed unsuccessful due to a 403 or 500 response, leading to the conclusion that it's not exploitable. In reality, the actual entry point is not a POST to config.xml, but the /job/{name}/configSubmit form submission interface, which accepts application/x-www-form-urlencoded data and requires a json parameter to carry the configuration. This detail is often missed even in professional penetration testing tool scripts.
Therefore, this article is not a "Jenkins RCE Reproduction Guide" but a "Record of CVE-2018-1000861's Triple Penetration Path." Its exploitation naturally involves three technical layers:
- Basic JavaScript execution (XSS level).
- Exploiting Jenkins' built-in Groovy sandbox escape mechanisms (Jenkins-specific).
- Invoking the underlying Java
Runtimeto execute system commands (the final payload). These layers are not strictly sequential; they can be triggered endependently or combined. One can prove the vulnerability's existence by simply displaying an alert box with pure JavaScript, or bypass the first two layers by directly using Groovy syntax to calljava.lang.Runtime.getRuntime().exec(). This layered nature makes it an excellent case study for beginners learning about web authorization model collapse and a covert channel for red teams to bypass Web Application Firewalls (WAFs) and Endpoint Detection and Response (EDR) systems, as no WAF would typically block a JSON request that appears to be merely modifying build parameters.
Who is this for? If you are a novice in penetration testing, this article will illustrate why "reading documentation is more important than running tools." If you are a DevSecOps engineer, you'll understand why Jenkins upgrades require more than just changing the version number—checking <security-constraint> configurations in web.xml is also crucial. If you are an organizational security lead, you'll grasp why the policy "disallow anonymous access to Jenkins" is ineffective against CVE-2018-1000861, as the exploit doesn't require authentication.
- Vulnerability Principle Breakdown: The Complete Call Chain from HTTP Request to Root Shell
2.1 Jenkins' Inherent Authorization Flaw: Why Can Anonymous Users Access configSubmit? To understand CVE-2018-1000861, one must first examine Jenkins' authorization design. Jenkins primarily uses Role-Based Access Control (RBAC), categorizing permissions into two types: Global permissions (e.g., Overall/Read, Job/Build) and Item-level permissions (e.g., Job/Configure, Job/Workspace). The critical point is that the Job/Configure permission, by default, does not verify user identity. Instead, it is dynamically determined by the hudson.security.AuthorizationStrategy implementation. In Jenkins versions 2.138.1 and earlier, the LegacyAuthorizationStrategy (the classic authorization strategy) implemented its hasPermission method for Job/Configure as follows:
public boolean hasPermission(Authentication a, Permission p) {
if (p == Job.CONFIGURE && !isAuthenticated(a)) {
return true; // Note: Returns true directly here
}
// Other permission checks...
}
This code explicitly states that if the current Authentication object is null (meaning the user is not authenticated) and the requested permission is Job.CONFIGURE, access is unconditionally granted. The /job/{name}/configSubmit endpoint uses Job.CONFIGURE as its authorization gate. This implies that any unauthenticated user, knowing a Job's name, can submit arbitrary configuration changes—including embedding malicious scripts.
Note: This logical flaw was not a bug but an intentional "convenience" feature in early Jenkins versions to support "public CI/CD pipelines." Only after the vulnerability's disclosure in 2018 did Jenkins change this logic to
return falsein version 2.138.2 and enforce CSRF protection.
2.2 configSubmit Interface Request Structure and Payload Construction Core The /job/{name}/configSubmit endpoint is a typical form submission interface. It does not accept raw XML or JSON bodies but expects data encoded as application/x-www-form-urlencoded. It primarily uses two parameters:
json: A JSON string describing the entire Job configuration structure. Thebuildersarray, under nodes likehudson.tasks.Shellorhudson.tasks.BatchFile, is a common target for traditional RCE. However, for CVE-2018-1000861, the key lies in embedding HTML+JS within thedescriptionfield.Submit: A fixed value ofSave, which triggers the form submission logic.
A minimal viable malicious request (using curl) is as follows:
curl -X POST "http://127.0.0.1:8080/job/test/configSubmit" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'json={"description": "<script>alert(\'XSS\');</script>", "jobs": []}&Submit=Save'