Skip to content

CVE-2026-84650: Verified Reproduction

CVE-2026-84650: Jenkins transient fields deserializable from config.xml → config object overwrite / RCE SECURITY-3972 companion

CVE-2026-84650 is verified against jenkinsci/jenkins · github. Affected versions: Jenkins weekly 2.579 and earlier; Jenkins LTS 2.568.2 and earlier. Vulnerability class: RCE. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00369.

REPRO-2026-00369 jenkinsci/jenkins · github RCE Sep 24, 2026 CVE entry .txt
Severity
HIGH
Confidence
HIGH
Reproduced in
60m 48s
Tool calls
461
Spend
$24.85
01 · Overview

What Is CVE-2026-84650?

CVE-2026-84650 is a high-severity RCE vulnerability affecting jenkinsci/jenkins Jenkins weekly 2.579 and earlier; Jenkins LTS 2.568.2 and earlier.. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00369).

02 · Severity & CVSS

CVE-2026-84650 Severity

CVE-2026-84650 is rated high severity.

HIGH threat level
Weakness CWE-502 — Deserialization of Untrusted Data

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected jenkinsci/jenkins Versions

jenkinsci/jenkins · github versions Jenkins weekly 2.579 and earlier; Jenkins LTS 2.568.2 and earlier. are affected.

How to Reproduce CVE-2026-84650

$ pruva-verify REPRO-2026-00369
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00369/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-84650

Remote code execution — reproduced
  • reached the target end-to-end
  • full exploit chain demonstrated
  • on the real production code path
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

Authenticated Item/Configure config.xml transient object graph followed by attacker-selected Groovy in a forged Stapler route

Attack chain
  1. POST /job/carrier/config.xml
  2. POST /job/carrier/pollingLog/run/project/parent/scriptText
How the agent worked 773 events · 461 tool calls · 1h 1m
1h 1mDuration
461Tool calls
56Reasoning steps
773Events
32Dead-ends
Agent activity over 1h 1m
Policy
1
Support
45
Repro
304
Judge
54
Variant
364
Verify
1
0:0060:39

Root Cause and Exploit Chain for CVE-2026-84650

Versions: component: Jenkins core, principally hudson.util.RobustReflectionConverter and security-sensitive transient fields in core model classes.Fixed: Jenkins weekly 2.580; Jenkins LTS 2.568.3.

CVE-2026-84650 (Jenkins SECURITY-4032) is an authenticated unsafe-deserialization flaw in Jenkins configuration updates. Jenkins historically excluded Java transient fields from serialization but still populated them while unmarshalling attacker-submitted config.xml. In Jenkins 2.579, an attacker with Item/Configure can therefore create a nested object graph whose transient ownership and identity links are attacker-selected. This run used the real Jenkins HTTP endpoint to set SCMTrigger.BuildAction.run, Run.project, AbstractItem.parent, and AbstractItem.name; Stapler then traversed that forged graph to a nested Jenkins object with an attacker-supplied unsecured authorization strategy, allowing arbitrary Groovy and operating-system command execution on the controller.

  • Affected component: Jenkins core, principally hudson.util.RobustReflectionConverter and security-sensitive transient fields in core model classes.
  • Affected versions: Jenkins weekly 2.579 and earlier; Jenkins LTS 2.568.2 and earlier.
  • Fixed versions: Jenkins weekly 2.580; Jenkins LTS 2.568.3.
  • Risk: High. An authenticated user able to update a job configuration can overwrite object identity/ownership state, forge Stapler traversal to privileged controller functions, and execute attacker-selected commands as the Jenkins controller process. The same primitive also corrupts protected cross-item state: this proof made a separate target job disappear from Jenkins' item map during an ordinary rename.

Impact Parity

  • Disclosed/claimed maximum impact: Controller code execution through the remote Jenkins configuration API.
  • Reproduced impact: Two fresh Jenkins 2.579 controller processes accepted crafted config.xml, exposed the forged /job/carrier/pollingLog/run/project/parent/scriptText route, evaluated attacker-selected Groovy, and ran /bin/sh to create unique controller-local marker files. Two Jenkins 2.580 controls accepted the same endpoint request but returned HTTP 404 on the forged route and created no marker.
  • Parity: full
  • Not demonstrated: No privilege beyond the Jenkins controller process account or host/container escape was attempted; neither is required by the claim.

Root Cause

AbstractItem.updateByXml(Source) checks Item.CONFIGURE, then unmarshals the submitted XML directly into the existing item using Items.XSTREAM2.unmarshal(..., this, ..., true). Before the fix, RobustReflectionConverter.fieldDefinedInClass treated every reflected field as deserializable, deliberately including Java transient fields for old-configuration compatibility. There was no field-level mechanism to reject attacker values for runtime-only identity, parent, owner, or execution references.

The exploit composes those writes as follows:

  1. The persistent Actionable.actions list receives hudson.triggers.SCMTrigger$BuildAction.
  2. Its transient run field receives a freshly constructed hudson.model.FreeStyleBuild.
  3. Run.project receives a nested FreeStyleProject.
  4. The nested project's transient AbstractItem.parent receives a nested jenkins.model.Jenkins.
  5. That nested Jenkins object's ordinary authorizationStrategy receives AuthorizationStrategy$Unsecured.
  6. Stapler follows carrier -> pollingLog -> run -> project -> parent -> scriptText. Jenkins.doScriptText checks the ACL of the nested Jenkins object, which now grants all permissions, rather than the real controller ACL. Attacker Groovy is evaluated on the real controller JVM and launches the selected command.

The same request sets transient AbstractItem.name to target. updateByXml calls onLoad afterward and restores the visible carrier name, but an ordinary rename records the injected value as oldName before restoration in the relevant flow and removes/replaces the protected item-map entry only on the vulnerable build. This supplies independent evidence of transient configuration-object overwrite.

The fix is commit 6244ebadf5b30257fde506c2d12d8eac9b6bc0e6 ([SECURITY-4032]). It adds @XStreamNotDeserializable / @XStreamDeserializable, teaches RobustReflectionConverter to skip forbidden transient fields, and annotates security-sensitive core fields including AbstractItem.name, AbstractItem.parent, Run.project, and SCMTrigger.BuildAction.run.

Reproduction Steps

  1. Run bundle/repro/reproduction_steps.sh from any directory. The script resolves its bundle through PRUVA_ROOT, reads bundle/project_cache_context.json, and uses the prepared repository location when available.
  2. The script pulls and verifies immutable Jenkins 2.579 and 2.580 JDK 21 image digests, downloads checksum-pinned Matrix Authorization Strategy dependencies, and creates four clean Jenkins controllers: two vulnerable and two fixed controls.
  3. Each controller is configured with an attacker account possessing Overall/Read, Item/Read, and Item/Configure, but not Overall/Administer; direct /script access is captured as denied.
  4. Through the real authenticated /job/carrier/config.xml endpoint, the script submits the crafted transient-field object graph. It then posts attacker-selected Groovy to the forged Stapler route and checks a unique controller-local command marker.
  5. It performs the secondary poisoned-name rename check, finalizes per-attempt request/response/service evidence, and writes bundle/repro/runtime_manifest.json with direct SHA-256 bindings.
  6. Expected result: both Jenkins 2.579 attempts show config=200 route=200 marker=true, while both 2.580 attempts show config=200 route=404 marker=false. The script exits 0 only if all vulnerable and fixed assertions hold.

Evidence

  • bundle/logs/reproduction_steps.log: top-level diagnostic transcript.
  • bundle/repro/runtime_manifest.json: immutable target identities and SHA-256 mapping for 48 finalized proof artifacts.
  • bundle/repro/proof/vulnerable_1.result.txt and vulnerable_2.result.txt: HTTP 200 on the config and forged script route, marker_present=true, target removed.
  • bundle/repro/proof/vulnerable_1.marker.txt and vulnerable_2.marker.txt: unique bytes written by attacker-selected /bin/sh commands.
  • bundle/repro/proof/vulnerable_1.config.request.xml: exact transient-field object graph sent through Item/Configure.
  • bundle/repro/proof/vulnerable_1.route.request.txt and .route.response.body: forged route and successful attacker Groovy output.
  • bundle/repro/proof/fixed_1.result.txt and fixed_2.result.txt: HTTP 404 on the same route, marker_present=false, and preserved target-secret state.
  • bundle/repro/proof/fixed_1.marker.txt and fixed_2.marker.txt: explicit absence records for unique fixed-control markers.
  • bundle/repro/proof/*_*.script.headers: direct Script Console controls showing X-Required-Permission: hudson.model.Hudson.Administer for the low-privilege user (supporting diagnostic evidence; the finalized manifest binds the per-attempt exploit records).
  • Vulnerable image: jenkins/jenkins@sha256:a7342867ea33efaacf825229d50b7fc77c144ecada9719ab4e32419f5d7412be, source release commit 9095ea3a5c5e7dcd392695a5dd880af1c9910ddf.
  • Fixed image: jenkins/jenkins@sha256:0e50a5b11ac14f3b84e529d725ed3a1c4b17ba16188dfa8d9a0189428b0839b1, source release commit 497de4961ad80d97e26bfdeb0d2e40442a84ecb0.

Key latest-run transcript:

[vulnerable/1] config=200 route=200 marker=true rename=302 target=404: owned=200:carrier-updated-through-config-api
[vulnerable/2] config=200 route=200 marker=true rename=302 target=404: owned=200:carrier-updated-through-config-api
[fixed/1] config=200 route=404 marker=false rename=302 target=200:target-secret owned=200:carrier-updated-through-config-api
[fixed/2] config=200 route=404 marker=false rename=302 target=200:target-secret owned=200:carrier-updated-through-config-api

Recommendations / Next Steps

  • Upgrade to Jenkins weekly 2.580 or newer, or LTS 2.568.3 or newer.
  • Do not enable the hudson.util.RobustReflectionConverter.DISABLE_XSTREAM_NOT_DESERIALIZABLE_CHECK escape hatch; it disables SECURITY-4032 protection.
  • Annotate plugin transient fields that encode identity, ownership, parentage, ACLs, runtime execution state, or object-root references with an annotation whose simple name is XStreamNotDeserializable, as supported for plugins targeting older cores.
  • Use @XStreamDeserializable only for reviewed migration-only transient fields and add vulnerable/fixed tests through real config.xml endpoints, not only direct XStream unit tests.
  • Audit plugin model types reachable from user-submitted configuration for unannotated transient Item, Run, Job, Node, User, ACL, or controller references.

Additional Notes

  • The final script passed two complete consecutive executions. Each execution itself launches two fresh vulnerable and two fresh fixed controller processes.
  • The primary proof is the normal Jenkins HTTP product path; no sanitizer, direct parser harness, or mocked response is used.
  • Rootless Docker emits a benign cgroup warning. The script uses a checksum-pinned Alpine cleanup image to remove subordinate-ID files left by interrupted runs and preserves caller-owned bundle paths.
  • The Matrix Authorization Strategy plugin is used only to establish the stated low-privilege precondition. Its downloaded bytes and dependency are checksum pinned. The vulnerability and exploit object graph are in Jenkins core.

CVE-2026-84650 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:003:12
0:00
session startedgpt-5.6-sol · CVE-2026-84650 · REPRO-20
0:06
0:08
web search
0:09
web search
0:10
web search
0:19
0:44
0:45
web search
0:47
web search
0:48
web search
1:04
web search
1:05
1:06
web search
1:07
web search
1:09
1:21
1:22
web search
1:23
web search
1:24
1:25
web search
1:45
web search
1:47
web search
1:48
web search
1:50
web search
1:53
2:38
2:38
2:59
3:08
web search
3:10
web search
3:11
web search
3:12
web search

Artifacts and Evidence for CVE-2026-84650

Scripts, logs, diffs, and output captured during the reproduction.

bundle/repro/proof/fixed_1.config.request.xml1.1 KB
bundle/repro/proof/fixed_1.config.response.headers0.4 KB
bundle/repro/proof/fixed_1.marker.txt0.0 KB
bundle/repro/proof/fixed_1.owned.response.json0.7 KB
bundle/repro/proof/fixed_1.rename.response.headers0.4 KB
bundle/repro/proof/fixed_1.result.txt0.3 KB
bundle/repro/proof/fixed_1.route.request.txt0.3 KB
bundle/repro/proof/fixed_1.route.response.body19.0 KB
bundle/repro/proof/fixed_1.route.response.headers1.1 KB
bundle/repro/proof/fixed_1.service.log4.5 KB
bundle/repro/proof/fixed_1.target.response.json0.7 KB
bundle/repro/proof/fixed_2.config.request.xml1.1 KB
bundle/repro/proof/fixed_2.config.response.headers0.4 KB
bundle/repro/proof/fixed_2.marker.txt0.0 KB
bundle/repro/proof/fixed_2.observation.json0.2 KB
bundle/repro/proof/fixed_2.owned.response.json0.7 KB
bundle/repro/proof/fixed_2.rename.response.headers0.4 KB
bundle/repro/proof/fixed_2.result.txt0.3 KB
bundle/repro/proof/fixed_2.route.request.txt0.3 KB
bundle/repro/proof/fixed_2.route.response.body19.0 KB
bundle/repro/proof/fixed_2.route.response.headers1.1 KB
bundle/repro/proof/fixed_2.service.log4.3 KB
bundle/repro/proof/fixed_2.target.response.json0.7 KB
bundle/repro/proof/vulnerable_1.config.response.headers0.4 KB
bundle/repro/proof/vulnerable_1.owned.response.json0.7 KB
bundle/repro/proof/vulnerable_1.rename.response.headers0.4 KB
bundle/repro/proof/vulnerable_1.result.txt0.3 KB
bundle/repro/proof/vulnerable_1.route.response.headers0.4 KB
bundle/repro/proof/vulnerable_1.target.response.json82.5 KB
bundle/repro/proof/vulnerable_2.config.response.headers0.4 KB
bundle/repro/proof/vulnerable_2.observation.json0.2 KB
bundle/repro/proof/vulnerable_2.owned.response.json0.7 KB
bundle/repro/proof/vulnerable_2.rename.response.headers0.4 KB
bundle/repro/proof/vulnerable_2.result.txt0.3 KB
bundle/repro/proof/vulnerable_2.route.response.headers0.4 KB
bundle/repro/proof/vulnerable_2.target.response.json82.5 KB
bundle/repro/rca_report.md9.4 KB
bundle/repro/reproduction_steps.sh15.8 KB
bundle/repro/runtime_manifest.json9.3 KB
bundle/repro/validation_verdict.json1.3 KB
08 · How to Fix

How to Fix CVE-2026-84650

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-84650 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-84650

Is CVE-2026-84650 exploitable?

Yes. Pruva independently reproduced CVE-2026-84650 in jenkinsci/jenkins and verified the exploit fires end-to-end in a sandboxed environment. A runnable proof-of-concept script and the full agent transcript are on this page (reproduction REPRO-2026-00369).

How severe is CVE-2026-84650?

CVE-2026-84650 is rated high severity.

What type of vulnerability is CVE-2026-84650?

CVE-2026-84650 is classified as CWE-502 (Deserialization of Untrusted Data), a RCE vulnerability.

Which versions of jenkinsci/jenkins are affected by CVE-2026-84650?

jenkinsci/jenkins Jenkins weekly 2.579 and earlier; Jenkins LTS 2.568.2 and earlier. is affected by CVE-2026-84650.

How can I reproduce CVE-2026-84650?

Pruva provides a verified reproduction script on this page. Download it and run it inside an isolated environment such as a container or virtual machine — never against production. The reproduction was confirmed end-to-end by Pruva's automated agents.

Is the CVE-2026-84650 reproduction verified?

Yes. Pruva reproduced CVE-2026-84650 with high confidence in a sandboxed environment, capturing the full agent transcript and artifacts as evidence.
11 · References

References for CVE-2026-84650

Authoritative sources for CVE-2026-84650 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.