CVE
CVE-2026-117612, CVE-2026-117613, CVE-2026-117614, CVE-2026-117615, CVE-2026-117616, CVE-2026-117617, CVE-2026-117618, CVE-2026-117619, CVE-2026-117620, CVE-2026-117621, CVE-2026-117622, CVE-2026-117623, CVE-2026-117624, CVE-2026-117625, CVE-2026-117626
CWE
CWE-502, CWE-22, CWE-59, CWE-362, CWE-285, CWE-79, CWE-613
Affected Surface
- Jenkins weekly versions `<= 2.587` (fixed in `2.588`)
- Jenkins LTS versions `<= 2.580.1` (fixed in `2.580.2`)
- CI/CD build controllers exposing `Overall/Read`, `Item/Configure`, or `Agent/Configure` permissions to developers, contractors, or automated webhooks
TL;DR
On 28 October 2026, the Jenkins project published Jenkins Security Advisory 2026-10-28 alongside weekly release 2.588 and Long-Term Support (LTS) release 2.580.2. The update patches 14 vulnerabilities in Jenkins core (CVE-2026-117612 through CVE-2026-117620 and CVE-2026-117621 through CVE-2026-117626), 12 of which are rated High severity.
Several of the bugs give users holding only Overall/Read or Item/Configure permissions a path to controller remote code execution or administrator account takeover:
- XStream
resolves-toJEP-200 filter bypass (SECURITY-4125/CVE-2026-117612, High): InRobustReflectionConverter.instantiateNewInstance(), when an XML element carried XStream’sresolves-toattribute, Jenkins calledmapper.realClass(readResolveValue)directly without checkingClassFilter.DEFAULT.isBlacklisted(...). Any authenticated user withOverall/Read(or any*/Configurepermission allowingPOST config.xml) could instantiate blacklisted gadget classes and reach controller RCE. Jenkins.getOrLoadNode()HTTP path traversal to arbitraryconfig.xmloverwrite (SECURITY-4188/CVE-2026-117616, High): Stapler exposedJenkins.getOrLoadNode(String nodeName)as a web-reachable route to anyone withOverall/Read, andNodes.load(String name)neither validatednamewithJenkins.checkGoodName()nor verified that the<name>inside the loaded XML matched the requested path. A caller withOverall/Readcould traverse to anyconfig.xmlon the controller filesystem, load it as an agent, and trigger a save that overwrote the targetconfig.xml.OldDataMonitoruser-account overwrite (SECURITY-4226/CVE-2026-117620, High): When a user submitted XML with obsolete/unrecognized fields viaPOST config.xml,RobustReflectionConverterrecorded the object inOldDataMonitor(“Manage Old Data”) just as if it had been loaded from disk. An attacker withOverall/Reador*/Configurecould poisonOldDataMonitorso that when an administrator reviewed and clicked Save in “Manage Old Data”, Jenkins overwrote a target user account’sconfig.xml(including its password hash onHudsonPrivateSecurityRealm).- Unauthenticated setup-wizard admin creation race (
SECURITY-4122/CVE-2026-117618), legacyagentCommandRCE (SECURITY-4123/CVE-2026-117614), and symlink file read/write (SECURITY-4187/CVE-2026-117615,SECURITY-4248/CVE-2026-117617): During initial setup, replacing the default admin account momentarily dropped the user count to zero whiledoCreateFirstAccountfailed to checkisSetupComplete(), letting an unauthenticated caller race in and create an admin account (CVE-2026-117618). Meanwhile,Slave.getLauncher()converted a legacyagentCommandXML field into a controllerCommandLauncherwithout script approval (CVE-2026-117614), job rename fallback copying followed symlinks (CVE-2026-117615), and parallel pipelinearchiveArtifactssteps could race symlink creation to write arbitrary files on the controller (CVE-2026-117617).
What to do now: Upgrade Jenkins weekly to 2.588 and Jenkins LTS to 2.580.2 immediately, and audit $JENKINS_HOME/users/, $JENKINS_HOME/nodes/, and OldDataMonitor entries for unexpected modifications.
Affected versions and CVE summary
| CVE | Advisory ID | Severity | Minimum privilege required | Summary & vulnerable component | Fixed in |
|---|---|---|---|---|---|
CVE-2026-117612 | SECURITY-4125 | High | Overall/Read (authenticated) or */Configure | RobustReflectionConverter.instantiateNewInstance() skipped ClassFilter.DEFAULT on resolves-to attributes, allowing arbitrary class instantiation and RCE | 2.588, 2.580.2 |
CVE-2026-117616 | SECURITY-4188 | High | Overall/Read | Stapler-exposed Jenkins.getOrLoadNode() and Nodes.load() allowed path traversal to load and overwrite arbitrary config.xml files on the controller | 2.588, 2.580.2 |
CVE-2026-117620 | SECURITY-4226 | High | Overall/Read | OldDataMonitor.report() accepted user-submitted XML errors, letting attackers overwrite admin user accounts (including passwords) when an admin saved Old Data | 2.588, 2.580.2 |
CVE-2026-117618 | SECURITY-4122 | High | Unauthenticated (during setup wizard) | HudsonPrivateSecurityRealm.doCreateFirstAccount() did not check isSetupComplete(), allowing an unauthenticated race to create an admin user while the initial user was replaced | 2.588, 2.580.2 |
CVE-2026-117614 | SECURITY-4123 | High | Agent/Configure | Slave.getLauncher() converted deprecated <agentCommand> XML fields into hudson.slaves.CommandLauncher without Script Security approval, executing commands on the controller JVM | 2.588, 2.580.2 |
CVE-2026-117615 | SECURITY-4187 | High | Item/Create + Item/Configure | AbstractItem.renameTo() fell back to copying the job directory when renameTo() failed, following symlinks to copy arbitrary controller files into the job workspace | 2.588, 2.580.2 |
CVE-2026-117617 | SECURITY-4248 | High | Item/Configure | TOCTOU symlink race during artifact extraction (FilePath / Util) allowed parallel pipeline branches to write arbitrary files on the controller filesystem | 2.588, 2.580.2 |
CVE-2026-117613 | SECURITY-4225 | High | Item/Configure | RobustReflectionConverter did not verify runtime element types of deserialized collections/maps against generic field declarations, enabling stored XSS | 2.588, 2.580.2 |
CVE-2026-117624 | SECURITY-4243 | High | */Configure | Incomplete PersistenceRoot check (SECURITY-3972 bypass) allowed top-level configuration types (User) to be deserialized as nested objects | 2.588, 2.580.2 |
CVE-2026-117619 | SECURITY-4189 | High | Valid API token | Requests authenticated via HTTP Basic + API token could mint a persistent “remember me” cookie that survived API token revocation or expiration | 2.588, 2.580.2 |
CVE-2026-117621, 117622, 117623 | SECURITY-4232, 4249, 4229 | High | Agent process (4232, 4249) or Overall/Read (4229) | Stored/agent-to-controller XSS via workspace browser links, agent exceptions implementing Stapler HttpResponse, and unescaped breadcrumb overflow tooltips | 2.588, 2.580.2 |
CVE-2026-117625, 117626 | SECURITY-4206, 4237 | Medium | Overall/Read | Missing permission check on HTTP proxy configuration endpoint (4206) and path-traversal metadata leak in workspace / userContent file browser (4237) | 2.588, 2.580.2 |
Technical analysis
1. CVE-2026-117612 (SECURITY-4125): XStream resolves-to attribute bypassed ClassFilter.DEFAULT
To defend against XStream deserialization gadgets that execute in #readResolve(), Jenkins enforces JEP-200 (hudson.remoting.ClassFilter.DEFAULT) through a custom Mapper wrapper inside XStream2. However, inside core/src/main/java/hudson/util/RobustReflectionConverter.java, instantiateNewInstance() looked up the resolves-to XML attribute and passed its value straight to mapper.realClass(readResolveValue) without checking ClassFilter.DEFAULT:
--- a/core/src/main/java/hudson/util/RobustReflectionConverter.java
+++ b/core/src/main/java/hudson/util/RobustReflectionConverter.java
@@ -660,8 +661,17 @@ private Class determineWhichClassDefinesField(HierarchicalStreamReader reader) {
protected Object instantiateNewInstance(HierarchicalStreamReader reader, UnmarshallingContext context) {
String readResolveValue = reader.getAttribute(mapper.aliasForAttribute("resolves-to"));
-
- Class type = readResolveValue != null ? mapper.realClass(readResolveValue) : context.getRequiredType();
+ Class type;
+ if (readResolveValue != null) {
+ type = mapper.realClass(readResolveValue);
+ String name = type.getName();
+ if (ClassFilter.DEFAULT.isBlacklisted(name) || ClassFilter.DEFAULT.isBlacklisted(type)) {
+ final String msg = "Refusing to instantiate resolves-to type '" + name + "'";
+ throw new CriticalXStreamException(new XStreamException(msg));
+ }
+ } else {
+ type = context.getRequiredType();
+ }
Commit 5c7550aba5 adds the explicit ClassFilter.DEFAULT.isBlacklisted() check on resolves-to classes and also wires XStream’s native TypePermission system into XStream2 as defense in depth.
2. CVE-2026-117616 (SECURITY-4188): Jenkins.getOrLoadNode() Stapler traversal and config.xml overwrite
In core/src/main/java/jenkins/model/Jenkins.java, the public method getOrLoadNode(String nodeName) lacked the @StaplerNotDispatchable annotation, allowing Stapler’s URL router to invoke it on HTTP requests from any user with Overall/Read.
When called, Nodes.load(String name) constructed getConfigFile(name) ($JENKINS_HOME/nodes/<name>/config.xml) without calling Jenkins.checkGoodName(name) and without verifying that the deserialized Node.getNodeName() matched the name parameter:
--- a/core/src/main/java/jenkins/model/Jenkins.java
+++ b/core/src/main/java/jenkins/model/Jenkins.java
@@ -2168,6 +2168,7 @@ public JDK getJDK(String name) {
@CheckForNull
@Restricted(Beta.class)
+ @StaplerNotDispatchable
public Node getOrLoadNode(String nodeName) {
return getNodesObject().getOrLoad(nodeName);
}
--- a/core/src/main/java/jenkins/model/Nodes.java
+++ b/core/src/main/java/jenkins/model/Nodes.java
@@ -408,10 +408,17 @@ public Node getOrLoad(String name) {
@CheckForNull
public Node load(String name) {
+ if (ENFORCE_NAME_RESTRICTIONS) {
+ Jenkins.checkGoodName(name);
+ }
+
try {
XmlFile xmlFile = getConfigFile(name);
if (xmlFile.exists()) {
Node n = (Node) xmlFile.read();
+ if (!name.equals(n.getNodeName())) {
+ throw new IOException("Node name " + n.getNodeName() + " in " + xmlFile + " does not match " + name);
+ }
By passing a relative traversal path (../../...) to getOrLoadNode, an attacker with Overall/Read could make Jenkins read any config.xml file on the controller filesystem as a Node whose <name> pointed at another path, register it in nodes, and cause subsequent saves to overwrite the target config.xml (commit c77d00fd3b).
3. CVE-2026-117620 (SECURITY-4226) and CVE-2026-117618 (SECURITY-4122): administrator account takeover via OldDataMonitor and setup-wizard race
Two separate bugs targeted Jenkins’s user management:
OldDataMonitorpoisoning (CVE-2026-117620, commit2516dd6846): WhenRobustReflectionConverterencountered an unrecognized XML element on aSaveableobject, it calledOldDataMonitor.report(Saveable, ...)so an administrator could click “Discard Unreadable Data” in Manage Jenkins -> Manage Old Data, which calls.save()on every recordedSaveable. BecauseOldDataMonitor.report()was not restricted toXmlFileloads from disk, user-submitted XML containing an embeddedUserobject with a bogus field registered that attacker-craftedUserinstance inOldDataMonitor. When an administrator later clicked the cleanup button in Manage Old Data, Jenkins saved the attacker’sUserobject to disk, overwriting the administrator’s password hash on controllers using Jenkins’s built-in user database.- Unauthenticated setup-wizard race (
CVE-2026-117618, commit5c180d1edc): InHudsonPrivateSecurityRealm.java,doCreateFirstAccount()only checkedif (hasSomeUser())before letting an unauthenticated HTTP request create an admin account. When an administrator completed the initial setup wizard by creating a named admin account, Jenkins deleted the initialadminuser before writing the new one, opening a window wherehasSomeUser()returnedfalsewhileisSetupComplete()was alsofalse:
--- a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
+++ b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
@@ -398,7 +398,7 @@ private String getErrorMessages(SignupInfo si) {
public synchronized void doCreateFirstAccount(StaplerRequest2 req, StaplerResponse2 rsp)
throws IOException, ServletException {
- if (hasSomeUser()) {
+ if (!Jenkins.get().getInstallState().isSetupComplete() || hasSomeUser()) {
rsp.sendError(SC_UNAUTHORIZED, "First user was already created");
return;
}
4. CVE-2026-117614 (SECURITY-4123), CVE-2026-117615 (SECURITY-4187), and CVE-2026-117617 (SECURITY-4248): legacy agentCommand RCE and symlink file read/write
- Legacy
<agentCommand>bypasses Script Security (CVE-2026-117614, commitdee305a355): For backward compatibility with Jenkins< 1.216,Slave.javakept a@Deprecated @XStreamDeserializable private transient String agentCommandfield. If an attacker withAgent/Configuresubmitted an agentconfig.xmlwithlauncheromitted and<agentCommand>...</agentCommand>set,Slave.getLauncher()reflectively instantiatedhudson.slaves.CommandLauncher(agentCommand, null)and calledsave()without checking whether an administrator had approved the command in Script Security.2.588and2.580.2delete theagentCommandfield and migration block entirely. - Symlink following on job rename (
CVE-2026-117615, commit37a111f9cb) and parallel artifact extraction (CVE-2026-117617, commit4a2ba37967): WhenAbstractItem.renameTo()failed to move a job directory atomically (for example while a file inside the directory was held open), it fell back to copying the directory tree and followed symbolic links on the controller filesystem (CVE-2026-117615). And when extracting archived build artifacts onto the controller,FilePathonly checked for symlinks before creating parent directories rather than immediately before opening the destination file, allowing two parallel Pipeline branches runningarchiveArtifactsto race a symlink into place and write arbitrary files outside the build directory (CVE-2026-117617).
Detection and remediation
# 1. Check running Jenkins version from the CLI, HTTP response header, or WAR manifest
curl -sI http://localhost:8080/login | grep -i 'X-Jenkins:' || true
# 2. Check Dockerfiles, Helm charts, and Kubernetes manifests for unpatched jenkins/jenkins tags
rg -n 'jenkins/jenkins(:|@|\s|$)' Dockerfile* docker-compose*.yml k8s/ helm/ .github/ 2>/dev/null
# 3. Audit $JENKINS_HOME for legacy <agentCommand> entries, resolves-to attributes, or suspicious symlinks
rg -n 'resolves-to|<agentCommand>' "${JENKINS_HOME:-/var/lib/jenkins}"/jobs/ "${JENKINS_HOME:-/var/lib/jenkins}"/nodes/ "${JENKINS_HOME:-/var/lib/jenkins}"/users/ 2>/dev/null
find "${JENKINS_HOME:-/var/lib/jenkins}/jobs" -type l -ls 2>/dev/null
- Upgrade Jenkins controllers immediately:
- Upgrade Jenkins weekly deployments to
2.588or later. - Upgrade Jenkins LTS deployments to
2.580.2or later (jenkins/jenkins:2.580.2-ltsorjenkins/jenkins:2.588).
- Upgrade Jenkins weekly deployments to
- Audit
OldDataMonitorand user accounts before clicking Save: Before using Manage Jenkins -> Manage Old Data -> Discard Unreadable Data on an unpatched controller, inspect the listed objects forhudson.model.Userentries (CVE-2026-117620), and verify$JENKINS_HOME/users/*/config.xmlfor unauthorized accounts created during setup (CVE-2026-117618). - Invalidate sessions if API tokens were revoked (
CVE-2026-117619): If you revoked or rotated a compromised Jenkins API token while running<= 2.587or<= 2.580.1, also rotate the user’s password or seed to invalidate any persistent “remember me” cookie minted with that token.
Timeline
- 2026-10-21 (12:14 to 12:15 UTC): Security fix commits
0679690b8cthroughc41ccc102c(SECURITY-4122throughSECURITY-4249) are committed to the Jenkins security branches andmaster/stable-2.580. - 2026-10-26: Release tags
jenkins-2.580.2(11:33 UTC) andjenkins-2.588(15:08 UTC) are prepared. - 2026-10-28 (16:19 UTC): The Jenkins project publishes Security Advisory
2026-10-28and posts the announcement forCVE-2026-117612throughCVE-2026-117626tooss-security(2026/10/28/6).
From research to remediation
Check whether this pattern exists in your codebase
Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.
References
- Jenkins Security Advisory 2026-10-28 (CVE-2026-117612 through CVE-2026-117626)
- oss-security: Multiple vulnerabilities in Jenkins (2.588 and LTS 2.580.2)
- jenkinsci/jenkins commit 5c7550aba5: apply ClassFilter to resolves-to attribute and enable XStream type permissions (SECURITY-4125 / CVE-2026-117612)
- jenkinsci/jenkins commit c77d00fd3b: block Stapler dispatch to getOrLoadNode and validate node names (SECURITY-4188 / CVE-2026-117616)
- jenkinsci/jenkins commit 2516dd6846: restrict OldDataMonitor reporting to disk loads (SECURITY-4226 / CVE-2026-117620)
- jenkinsci/jenkins commit 5c180d1edc: require completed setup wizard in doCreateFirstAccount (SECURITY-4122 / CVE-2026-117618)
- jenkinsci/jenkins commits 37a111f9cb, 4a2ba37967, and dee305a355 (SECURITY-4187, SECURITY-4248, SECURITY-4123)