← Back to Feed CACHED · 2026-10-29 00:39:34 · CACHE_KEY CVE-2026-117612
CVE-2026-117612 · CWE-502 · Disclosed 2026-10-28

Jenkins XStream deserialization filter bypass via resolves-to attribute

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Someone left the castle's back gate unbolted because the guard only checks IDs at the front door, not the service entrance marked 'resolves-to'

CVE-2026-117612 (SECURITY-4125) is a deserialization filter bypass in Jenkins core. Jenkins uses XStream to serialize and deserialize configuration data — job configs, views, agent definitions — as XML. Since JEP-200, Jenkins maintains a strict allowlist of types that may be deserialized. However, Jenkins' custom XStream converter failed to apply this filter to classes referenced by the resolves-to XML attribute. An attacker who can POST a crafted config.xml (requiring Overall/Read plus Item/Configure, View/Configure, or Agent/Configure permission) can reference an arbitrary Java class via resolves-to, bypass the entire JEP-200 allowlist, instantiate a dangerous gadget class, and achieve remote code execution on the Jenkins controller. Affected versions: Jenkins weekly ≤2.587 and LTS ≤2.580.1. Fixed in weekly 2.588 and LTS 2.580.2, disclosed 2026-10-28.

The Jenkins project rates this High, and the CVSS vector they published (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H = 8.8) is a fair technical description of the auth-required, network-reachable, full-CIA-impact chain. However, CVSS does not account for *what* the target is. Jenkins controllers are the nerve center of CI/CD pipelines: they hold deployment credentials, signing keys, source-code access tokens, and orchestrate builds that ship to production. RCE on a Jenkins controller is not an 8.8-level event — it is a supply-chain-scale compromise. The vendor severity underweights the blast radius by treating Jenkins like a generic web application rather than the crown-jewel CI/CD infrastructure it is.

"Jenkins XStream filter bypass lets any config-level user achieve RCE on the CI/CD controller — patch to 2.588 now"
02 · The Attack Path

5 steps from start to impact.

STEP 01

Authenticate to Jenkins

The attacker obtains a valid Jenkins session — either through a compromised developer account, a leaked API token, or an insider threat. Jenkins exposes its web UI over HTTP(S) on port 8080 by default. Many organizations federate Jenkins auth via LDAP or SAML, meaning any domain credential may suffice.
Conditions required:
  • Valid Jenkins account with Overall/Read permission
  • Network access to Jenkins controller (port 8080 or reverse-proxied)
Where this breaks in practice:
  • Jenkins is rarely internet-facing in mature enterprises — typically behind VPN or corporate network
  • Account requires Overall/Read, which is the minimum useful permission but still requires authentication
Detection/coverage: Failed login attempts visible in Jenkins access log and SIEM; brute-force detectable via rate limiting or account lockout policies
STEP 02

Identify a writable config endpoint

The attacker needs a permission that allows POSTing XML configuration. Item/Configure (the most common), View/Configure, or Agent/Configure all qualify. In most Jenkins deployments, developers and pipeline engineers hold Item/Configure on at least some jobs. The attacker identifies a job, view, or agent they can configure and targets its config.xml REST endpoint.
Conditions required:
  • One of: Item/Configure, View/Configure, or Agent/Configure on at least one object
Where this breaks in practice:
  • Least-privilege Jenkins deployments restrict Item/Configure to pipeline admins only
  • Matrix Authorization or Role Strategy plugins can limit who configures what
Detection/coverage: Jenkins audit trail plugin logs config.xml POST requests; unusual config changes on jobs the user doesn't normally touch would stand out
STEP 03

Craft malicious XML with resolves-to gadget

The attacker constructs an XML payload where a legitimate top-level element passes the JEP-200 type filter, but includes a resolves-to attribute referencing a dangerous class on Jenkins' classpath — such as Groovy's MethodClosure, a Spring gadget, or a Commons Collections transformer chain. Because the custom converter does not apply the deserialization filter to the resolves-to target class, the gadget is instantiated unchecked. The technique mirrors historical XStream CVEs (CVE-2021-39148, CVE-2021-39145) where type-substitution attributes were used to smuggle disallowed types past allowlists.
Conditions required:
  • Knowledge of available gadget classes on Jenkins' classpath
  • Ability to craft XStream XML with resolves-to attribute
Where this breaks in practice:
  • No public PoC exists as of 2026-10-29, raising the bar for unsophisticated attackers
  • Available gadget classes depend on installed plugins — a minimal Jenkins install has fewer gadgets than a plugin-heavy one
Detection/coverage: WAF or reverse proxy rules inspecting XML bodies for resolves-to attributes containing known gadget class names; Snort/Suricata signatures for XStream exploitation patterns
STEP 04

POST payload to config.xml endpoint

The attacker submits the crafted XML via POST /job/<name>/config.xml (or the equivalent view/agent endpoint) with their authenticated session. Jenkins accepts the XML and passes it to XStream for deserialization. The converter processes the resolves-to attribute without filtering, instantiating the attacker's chosen class.
Conditions required:
  • Authenticated session from Step 1
  • Config permission from Step 2
  • Crafted payload from Step 3
Where this breaks in practice:
  • Content-Security-Policy headers and CRUMB tokens must be handled — standard for Jenkins API interaction but adds minor complexity
  • Some WAFs may block suspicious XML payloads
Detection/coverage: Jenkins audit trail shows the config.xml POST; IDS/IPS with XStream deserialization signatures may flag the payload
STEP 05

Achieve RCE on Jenkins controller → supply-chain pivot

The gadget chain executes arbitrary code as the Jenkins process user (often jenkins on Linux or SYSTEM on Windows). The attacker now has full control of the CI/CD controller: access to all stored credentials (via /credentials/), ability to modify any pipeline, inject malicious build steps, exfiltrate source code, poison build artifacts, or pivot laterally to deployment targets. On Windows controllers running as SYSTEM, this also means local privilege escalation. The attacker can persist by installing a malicious plugin or modifying init scripts.
Conditions required:
  • Successful deserialization of gadget chain
  • Jenkins process user has access to credential store and pipeline definitions
Where this breaks in practice:
  • Credential rotation and secrets management (e.g., HashiCorp Vault integration) limits the shelf-life of stolen secrets
  • Pipeline-as-code (Jenkinsfile in SCM) makes artifact poisoning more detectable via git diffs
Detection/coverage: Unexpected process execution from Jenkins user detected by EDR; credential access patterns in Jenkins audit log; build artifact hash mismatches in artifact integrity monitoring
03 · Compensating Control

1
CRITICAL 9.1→IGNORE 0.0
SEVERITY REDUCED
Upgrade to Jenkins 2.588 or LTS 2.580.2 immediately — The definitive fix. Jenkins 2.588 and LTS 2.580.2 apply the deserialization filter to resolves-to classes and add XStream type permission checks. Per the noisgate mitigation SLA for CRITICAL, deploy within 3 days. Test in staging first — the new type permission checks may reject legitimate plugin serialization patterns. If breakage occurs, the system property hudson.util.XStream2.SUPPRESS_TYPE_PERMISSION=true can temporarily disable the new checks, but this re-opens the vulnerability and must be a time-boxed exception.
2
CRITICAL 9.1→HIGH 7.2
SEVERITY REDUCED
Restrict Item/Configure, View/Configure, and Agent/Configure permissions to pipeline admins only — Use the Matrix Authorization Strategy or Role-Based Access Strategy plugin to ensure only a small, audited set of administrators can POST config.xml. Remove Item/Configure from all developer and QA roles. This directly breaks Step 2 of the attack path by eliminating the attacker's ability to submit crafted XML. Deploy within 3 days per noisgate mitigation SLA for CRITICAL.
3
CRITICAL 9.1→HIGH 7.0
SEVERITY REDUCED
Place Jenkins behind VPN or zero-trust network access with MFA — Ensure Jenkins is not directly reachable from the internet or from untrusted network segments. Require MFA for all Jenkins access. This does not fix the vulnerability but drastically raises the bar for exploitation by requiring network-level access and a second authentication factor before the attacker can even reach the vulnerable endpoint. Deploy within 3 days.
4
CRITICAL 9.1→HIGH 7.5
SEVERITY REDUCED
Deploy WAF rules blocking resolves-to in XML POST bodies to Jenkins config endpoints — Configure your WAF or reverse proxy to inspect HTTP POST bodies to /*/config.xml endpoints and block requests containing resolves-to attributes referencing classes outside a known-good allowlist. This is a defense-in-depth measure — it can be bypassed with encoding tricks but raises the bar significantly. Use ModSecurity, AWS WAF, or Cloudflare custom rules.
5
CRITICAL 9.1→CRITICAL 9.1
Enable Jenkins audit trail plugin and alert on config.xml modifications — Install and configure the Audit Trail plugin to log all config.xml POST requests with the authenticated user identity. Forward logs to SIEM and create alerts for config changes to jobs the modifying user doesn't normally touch. This is a detection control, not prevention — it reduces dwell time from days to minutes if exploitation occurs.
What doesn't work
  • Setting SUPPRESS_TYPE_PERMISSION=true — this system property *disables* the fix introduced in 2.588/2.580.2. It exists for compatibility, not security. Setting it re-opens CVE-2026-117612 entirely.
  • Jenkins Script Security plugin — Script Security governs Groovy sandbox execution in pipelines, not XStream deserialization. The vulnerable code path runs before Script Security is invoked.
  • Disabling anonymous read access — the vulnerability already requires authentication. If you didn't have anonymous access before, this changes nothing. If you did, disabling it doesn't help because the attacker needs Item/Configure, which anonymous users never have.
  • Upgrading XStream library alone — this is a Jenkins converter bug, not an upstream XStream bug. The XStream library itself passes the resolves-to class to Jenkins' custom converter, which fails to filter it. Only the Jenkins core fix addresses this.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo confirmed exploitation. Not listed in CISA KEV. SecurityOnline reports status as 'Not exploited' as of 2026-10-28. This is a 1-day-old disclosure; exploitation status should be monitored closely given Jenkins' history as a high-value target.
Proof-of-conceptNo public PoC found. No repositories on GitHub, no entries on pocindex.io or ExploitDB. However, the technique is well-understood: prior XStream type-substitution bypasses (CVE-2021-39148, CVE-2021-39145, CVE-2020-26217) have published PoCs and Metasploit modules (exploit/multi/http/jenkins_xstream_deserialize). Weaponization is likely a matter of days to weeks for skilled researchers.
EPSSNot yet scored — CVE was published 2026-10-28 and EPSS has not ingested it. For reference, the prior Jenkins XStream RCE CVE-2026-84645 (SECURITY-3972, September 2026) carries an EPSS of 0.66 (66th percentile) per Bitsight, indicating high predicted exploitation probability for this class of bug.
KEV statusNot listed in CISA Known Exploited Vulnerabilities catalog as of 2026-10-29.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H = 8.8 (High) per the Jenkins advisory. Network-reachable, low complexity, low privilege required (authenticated), no user interaction. Full CIA impact. The Scope:Unchanged is accurate — exploitation stays on the Jenkins controller, though the *business* blast radius extends to the entire software supply chain.
Affected versionsJenkins weekly ≤2.587; LTS ≤2.580.1. VulDB incorrectly lists the range as up to 2.579.x — use the Jenkins advisory as authoritative.
Fixed versionsJenkins weekly 2.588; LTS 2.580.2. Both released 2026-10-28. No distro backports identified yet — Debian, Red Hat, and FreeBSD packages should be monitored for updates. Docker image jenkins/jenkins:2.588 and jenkins/jenkins:2.580.2-lts are the targets.
Exposure dataShadowserver identified ~45,000 internet-facing Jenkins instances globally in January 2024 (during CVE-2024-23897). Current numbers are likely similar. Most are in the US (~11,800) and China (~12,000). However, the majority of enterprise Jenkins instances are internal — Shodan/Censys only see a fraction of the installed base. The auth requirement makes internet exposure less relevant than internal exposure.
Disclosure timelineReserved 2026-10-27, published 2026-10-28 in Jenkins Security Advisory 2026-10-28. SECURITY-4125. Part of a 15-CVE advisory batch.
Researcher / reporterNot publicly credited in available sources. The Jenkins advisory (SECURITY-4125) does not name the reporter in the materials retrieved.

Sources.

  1. Jenkins Security Advisory 2026-10-28 (SECURITY-4125)
  2. CVE-2026-117612 — ThreatInt CVE Database
  3. CVE-2026-117612 — Strix AI
  4. Jenkins Fixes 15 Vulnerabilities — SecurityOnline
  5. Bitsight CVE-2026-84645 (prior Jenkins XStream RCE, EPSS reference)
  6. Shadowserver — 45K Jenkins Instances Exposed (exposure baseline)
  7. Metasploit Jenkins XStream Deserialize Module (historical technique reference)
  8. Red Hat — Java Deserialization Flaws Part 2: XML Deserialization (XStream technique background)
05 · The Call

Final Verdict
↑ UPGRADED to CRITICAL (9.1/10)

Why this verdict

  • Filter bypass yields full RCE: The resolves-to attribute bypass completely defeats JEP-200, Jenkins' primary deserialization defense. Once bypassed, the attacker has the same primitive as pre-JEP-200 Jenkins: arbitrary class instantiation during deserialization, which reliably chains to code execution via well-known gadgets (Groovy, Commons Collections, Spring) present on Jenkins' classpath.
  • Authentication is real friction but not high friction: The chain requires Overall/Read + Item/Configure. In practice, most Jenkins environments grant Item/Configure to dozens or hundreds of developers and pipeline engineers. A single compromised developer laptop, leaked API token, or malicious insider satisfies this prerequisite. This is PR:L, not PR:H — and the population of users who hold this permission is large relative to the organization.
  • No user interaction, low complexity: The attack is a single authenticated API call — POST /job/<name>/config.xml with crafted XML. No race conditions, no memory corruption, no multi-step social engineering. Once you have the creds and the payload, it's deterministic.
  • Role multiplier: Jenkins is *canonically* a CI/CD controller — 100% of its installed base serves this role. RCE on the Jenkins controller delivers: (1) access to all stored credentials (deployment keys, cloud API tokens, registry passwords, signing certificates), (2) ability to inject malicious code into any build pipeline, (3) supply-chain compromise of every artifact built by that instance, (4) lateral movement to production environments via deployment pipelines. The blast radius is supply-chain-scale. Per the deployment-role blast radius rule, because Jenkins is canonically a high-value CI/CD component and the chain succeeds with supply-chain-pivot outcome, the verdict floor is CRITICAL.
  • Historical pattern: Jenkins XStream deserialization bugs are reliably weaponized. CVE-2016-0792 had a Metasploit module. CVE-2026-53435 (same bug class, June 2026) is reported as actively exploited. CVE-2026-84645 (September 2026) has an EPSS of 0.66. The absence of a PoC today does not mean absence next week — the technique is public and well-documented.

Why not higher?

A 9.1 already reflects the supply-chain blast radius. It is not 9.8–10.0 because the chain requires authenticated access with a specific permission set (PR:L), which meaningfully narrows the attacker population compared to a pre-auth RCE. If this were exploitable by anonymous users or unauthenticated attackers, it would be 9.8+.

Why not lower?

Downgrading below CRITICAL would require evidence that fewer than 10% of Jenkins installations serve a CI/CD role — which is definitionally impossible since Jenkins *is* a CI/CD tool. The authentication requirement is real friction, but friction cannot pull below the floor set by the blast radius. Every Jenkins controller holds credentials, orchestrates builds, and touches production deployments. An 8.8 (High) rating treats this like RCE on a blog server; it is RCE on the software factory.

06 · Verification

Crowdsourced verification payload.

Run this script from any workstation that has curl and network access to the Jenkins controller. Pass the Jenkins URL as the first argument. No authentication is required — the script reads the X-Jenkins response header, which is returned on unauthenticated requests to the login page. Example: ./check_cve_2026_117612.sh https://jenkins.example.com:8080

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-117612 checker — Jenkins XStream resolves-to deserialization filter bypass
# Usage: ./check_cve_2026_117612.sh <JENKINS_URL>
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -uo pipefail

JENKINS_URL="${1:?Usage: $0 <JENKINS_URL>}"
JENKINS_URL="${JENKINS_URL%/}"

# Retrieve Jenkins version from X-Jenkins header
VERSION=$(curl -sI --max-time 10 "${JENKINS_URL}/login" 2>/dev/null \
  | grep -i '^X-Jenkins:' \
  | awk '{print $2}' \
  | tr -d '\r\n ')

if [[ -z "$VERSION" ]]; then
  echo "UNKNOWN — could not retrieve Jenkins version from ${JENKINS_URL}"
  echo "Verify the URL is correct and the server is reachable."
  exit 2
fi

echo "Detected Jenkins version: ${VERSION}"

# Semantic version comparison: returns 0 if $1 >= $2
version_ge() {
  printf '%s\n%s' "$2" "$1" | sort -V -C
}

# Determine release line by segment count
IFS='.' read -ra PARTS <<< "$VERSION"

if [[ ${#PARTS[@]} -ge 3 ]]; then
  # LTS release (e.g., 2.580.2) — fixed in 2.580.2
  FIXED="2.580.2"
  if version_ge "$VERSION" "$FIXED"; then
    echo "PATCHED — LTS ${VERSION} >= ${FIXED}"
    exit 0
  else
    echo "VULNERABLE — LTS ${VERSION} < ${FIXED} (CVE-2026-117612)"
    echo "Action: Upgrade to Jenkins LTS ${FIXED} or later."
    exit 1
  fi
else
  # Weekly release (e.g., 2.588) — fixed in 2.588
  FIXED="2.588"
  if version_ge "$VERSION" "$FIXED"; then
    echo "PATCHED — Weekly ${VERSION} >= ${FIXED}"
    exit 0
  else
    echo "VULNERABLE — Weekly ${VERSION} < ${FIXED} (CVE-2026-117612)"
    echo "Action: Upgrade to Jenkins Weekly ${FIXED} or later."
    exit 1
  fi
fi