Skip to content

CVE-2026-84647: Verified Reproduction

CVE-2026-84647: Jenkins Stapler form binding instantiates arbitrary config types → RCE SECURITY-3966

CVE-2026-84647 is verified against jenkinsci/jenkins · github. Vulnerability class: RCE. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00349.

REPRO-2026-00349 jenkinsci/jenkins · github RCE Sep 11, 2026 CVE entry .txt
Severity
HIGH
Confidence
HIGH
Reproduced in
51m 2s
Tool calls
422
Spend
$19.62
01 · Overview

What Is CVE-2026-84647?

CVE-2026-84647 is a high-severity RCE vulnerability affecting jenkinsci/jenkins. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00349).

02 · Severity & CVSS

CVE-2026-84647 Severity

CVE-2026-84647 is rated high severity.

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

High — serious impact or readily exploitable. Prioritize remediation.

How to Reproduce CVE-2026-84647

$ pruva-verify REPRO-2026-00349
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00349/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-84647

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 multipart structured form data whose ListView columns stapler-class-bag selects StashedFileParameterValue, including an uploaded Groovy file and traversal name

Attack chain
  1. POST /user/alice/my-views/createView
  2. Stapler RequestImpl collection bindJSON
  3. incompatible @DataBoundConstructor
  4. JENKINS_HOME/init.groovy.d write
  5. controller restart
How the agent worked 714 events · 422 tool calls · 51 min
51 minDuration
422Tool calls
65Reasoning steps
714Events
31Dead-ends
Agent activity over 51 min
Policy
1
Support
43
Repro
373
Judge
37
Variant
255
Verify
1
0:0050:51

Root Cause and Exploit Chain for CVE-2026-84647

Versions: component: Jenkins core's bundled Stapler structured form-binding implementation, specifically collection conversion in org.kohsuke.stapler.RequestImpl.TypePair.convertJSON.

Jenkins 2.579 bundles Stapler 2107.v8dfcb_e8ed317, whose structured-form collection binder trusts every class name encoded as a key beneath stapler-class-bag. It loads and instantiates the requested class without first checking that the class is a subtype of the collection's declared item type. An authenticated user with only Overall/Read can reach the personal My Views creation endpoint and submit a ListView.columns collection that names an unrelated configuration class. In this run, the attacker selected io.jenkins.plugins.file_parameters.StashedFileParameterValue; its data-bound constructor consumed an uploaded file and an attacker-controlled traversal name, placing attacker Groovy under JENKINS_HOME/init.groovy.d. On an ordinary Jenkins restart, the real controller executed the Groovy startup hook and created a unique command-execution marker. Jenkins 2.580 reached the same endpoint but ignored the incompatible class before construction.

  • Affected component: Jenkins core's bundled Stapler structured form-binding implementation, specifically collection conversion in org.kohsuke.stapler.RequestImpl.TypePair.convertJSON.
  • Affected versions: Stapler 2107.v8dfcb_e8ed317 and earlier, except 2088.2093.vd7c3e58008a_6; included in Jenkins weekly 2.579 and earlier and Jenkins LTS 2.568.2 and earlier. The issue is fixed in Jenkins weekly 2.580 and LTS 2.568.3.
  • Tested vulnerable target: Immutable image jenkins/jenkins@sha256:a7342867ea33efaacf825229d50b7fc77c144ecada9719ab4e32419f5d7412be (Jenkins 2.579, source commit 9095ea3a5c5e7dcd392695a5dd880af1c9910ddf).
  • Tested fixed target: Immutable image jenkins/jenkins@sha256:0e50a5b11ac14f3b84e529d725ed3a1c4b17ba16188dfa8d9a0189428b0839b1 (Jenkins 2.580, source commit 497de4961ad80d97e26bfdeb0d2e40442a84ecb0).
  • Risk: High. A network attacker with only Overall/Read can invoke constructors and setters of configuration-related classes outside the intended destination type. Impact depends on available data-bound gadget classes. With File Parameter Plugin 425.v3fa_801681b_5e, the run demonstrated a controller file-write gadget and persistent controller-side code execution after restart. The low-privilege user was denied direct Script Console access.

Impact Parity

  • Disclosed/claimed maximum impact: Remote code execution on the Jenkins controller.
  • Reproduced impact from this run: Full controller code execution. Two independent low-privilege HTTP submissions placed attacker-selected Groovy in JENKINS_HOME/init.groovy.d; after restarting each controller, Jenkins' real GroovyHookScript executed it and created a unique marker.
  • Parity: full.
  • Not demonstrated: Immediate, restart-free command execution was not required or demonstrated. The proven chain requires a later controller restart and the installed File Parameter Plugin 425 gadget. No sanitizer, direct unit harness, administrative token, Script Console, or Item/Configure permission was used for the attack.

Root Cause

For collection-valued form fields, Stapler recognizes a JSON object containing "stapler-class-bag": true. In vulnerable RequestImpl.TypePair.convertJSON, it iterates over all object entries, converts each entry key from JSON-safe - escaping back to ., and performs:

Class<?> itemType = cl.loadClass(className);
l.add(bindJSON(itemType, (JSONObject) v));

Although the collection lister carries the expected element class as l.itemType, the vulnerable code never checks l.itemType.isAssignableFrom(itemType) before recursively binding and constructing the attacker-selected class. Type incompatibility is discovered only later, if at all; constructor and setter side effects have already occurred. The low-privilege personal-view endpoint is exploitable because creating a personal view is permitted with Overall/Read and ListView has a data-bound List<ListViewColumn> property.

The security fix is Stapler commit b49b34c07103fb238a566e51b531729f1b68e73d (SECURITY-3915). It changes class loading to:

Class<?> itemType = cl.loadClass(className).asSubclass(l.itemType);

and catches ClassCastException together with ClassNotFoundException. Consequently, Jenkins 2.580 ignores StashedFileParameterValue when binding ListView.columns because it is not a ListViewColumn, so its constructor never receives the upload and cannot create the startup hook.

Reproduction Steps

  1. Run bundle/repro/reproduction_steps.sh with Bash and a working Docker daemon.
  2. The script reads bundle/project_cache_context.json when available, otherwise uses bundle/artifacts/jenkins-security-3915; downloads checksum-pinned plugins; and uses immutable Jenkins 2.579 and 2.580 image digests.
  3. For each target, it starts clean controller processes with matrix authorization granting alice only Overall/Read. It proves the restriction with GET /script returning HTTP 403.
  4. It sends an authenticated multipart POST /user/alice/my-views/createView. The submitted ListView.columns.stapler-class-bag names StashedFileParameterValue, and the uploaded file is attacker Groovy whose constructor argument places it at ../../init.groovy.d/cve84647.groovy relative to the gadget's temporary directory.
  5. It restarts the real Jenkins controller and checks for a unique target-local marker written by that Groovy.
  6. The script performs two clean Jenkins 2.579 attempts and two clean Jenkins 2.580 controls, emits bundle/repro/runtime_manifest.json, verifies every bound artifact hash, and exits 0 only for the expected vulnerable/fixed divergence.
  7. Expected terminal output includes:
CONFIRMED vulnerable attempt 1: low-privilege request executed attacker Groovy after restart
CONFIRMED vulnerable attempt 2: low-privilege request executed attacker Groovy after restart
CONFIRMED fixed attempt 1: target path reached but incompatible class constructor did not run
CONFIRMED fixed attempt 2: target path reached but incompatible class constructor did not run
CVE-2026-84647 CONFIRMED: two low-privilege production HTTP attempts achieved controller code execution; two fixed controls failed closed.

Evidence

  • bundle/repro/runtime_manifest.json: strict runtime manifest with 42 immutable proof artifacts and SHA-256 bindings.
  • bundle/repro/proof/vulnerable_1.request.json and vulnerable_2.request.json: attacker request shape crossing the actual Jenkins HTTP endpoint.
  • bundle/repro/proof/vulnerable_1.response.headers and vulnerable_2.response.headers: endpoint responses.
  • bundle/repro/proof/vulnerable_1.privilege.txt and vulnerable_2.privilege.txt: GET /script HTTP 403, proving the attacker did not have Overall/Administer.
  • bundle/repro/proof/vulnerable_1.result.txt and vulnerable_2.result.txt: each records payload_script_present=true and marker_present=true.
  • bundle/repro/proof/vulnerable_1.marker.txt and vulnerable_2.marker.txt: unique controller-local command markers.
  • bundle/repro/proof/vulnerable_1.service.log and vulnerable_2.service.log: real Jenkins lifecycle logs. Each includes Starting version 2.579 and Executing /var/jenkins_home/init.groovy.d/cve84647.groovy after restart.
  • bundle/repro/proof/fixed_1.result.txt and fixed_2.result.txt: same endpoint reached on Jenkins 2.580, but payload_script_present=false and marker_present=false.
  • bundle/repro/proof/fixed_1.negative_control.json and fixed_2.negative_control.json: explicit target-reached fixed observations.
  • bundle/repro/proof/fixed_1.service.log and fixed_2.service.log: Jenkins 2.580 starts and restarts without executing the attacker hook.
  • bundle/logs/reproduction_steps.log: concise final-run diagnostic summary.

A final vulnerable log excerpt is:

Starting version 2.579
Executing /var/jenkins_home/init.groovy.d/cve84647.groovy
Jenkins is fully up and running

The corresponding fixed result is:

POST /user/alice/my-views/createView HTTP 302
payload_script_present=false
marker_present=false

The final script was executed twice consecutively. Both complete runs exited 0 (approximately 63 seconds and 58 seconds) and reproduced two vulnerable executions plus two fixed controls on each run.

Recommendations / Next Steps

  • Upgrade Jenkins weekly to 2.580 or newer, or Jenkins LTS to 2.568.3 or newer.
  • Ensure the bundled Stapler version contains commit b49b34c07103fb238a566e51b531729f1b68e73d or an equivalent backport.
  • Independently upgrade plugins fixed in the 2026-09-02 advisory. In particular, update File Parameter Plugin to 433.va_0b_80359d54d or newer; this removes the traversal primitive used in the demonstrated composition.
  • Audit @DataBoundConstructor and @DataBoundSetter methods for side effects and permission checks. Constructors should not write files, initiate network connections, modify global state, or execute commands merely as a consequence of binding.
  • Add regression tests for every structured-form collection syntax, especially stapler-class-bag, proving that unrelated classes are rejected before constructors or setters execute.
  • Monitor JENKINS_HOME/init.groovy.d, plugin configuration files, and unexpected controller restarts for evidence of persistence. Rotate secrets if compromise is suspected.

Additional Notes

  • Idempotency: Confirmed. The final reproducer passed twice consecutively and uses isolated Docker volumes, unique container names, unique marker values, bounded health checks, and cleanup traps.
  • Runtime boundary: Production Jenkins HTTP/Stapler endpoint, not a direct parser call or unit harness.
  • Sanitizers: None used.
  • Exploit preconditions: Authenticated Overall/Read access; an available configuration-related data-bound gadget (File Parameter Plugin 425 in this proof); write access of the Jenkins process to its own home; and a later controller restart for startup-hook execution.
  • Endpoint behavior: Both vulnerable and fixed versions return HTTP 302 because the outer personal ListView remains valid. Security is proven by the constructor side effect and marker divergence, not status code alone.
  • Scope limitation: The demonstrated file gadget comes from an affected plugin. The root vulnerability itself is in Stapler and permits incompatible class selection; other installed classes may provide different consequences.

CVE-2026-84647 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:03
0:01
session startedgpt-5.6-sol · CVE-2026-84647 · REPRO-20
0:06
0:07
web search
0:09
web search
0:23
0:27
0:33
0:34
web search
0:35
web search
0:37
web search
0:44
0:45
web search
0:47
web search
0:48
web search
0:58
web search
1:00
web search
1:01
web search
1:04
1:20
1:22
web search
1:23
web search
1:25
web search
1:46
1:48
web search
1:49
web search
1:50
web search
3:03
3:03
3:03
3:03
3:03
3:03

Artifacts and Evidence for CVE-2026-84647

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

bundle/logs/reproduction_steps.log0.8 KB
bundle/repro/proof/fixed_1.health.after-restart.txt0.0 KB
bundle/repro/proof/fixed_1.health.txt0.0 KB
bundle/repro/proof/fixed_1.identity.txt0.1 KB
bundle/repro/proof/fixed_1.marker.txt0.0 KB
bundle/repro/proof/fixed_1.privilege.txt0.1 KB
bundle/repro/proof/fixed_1.request.json0.6 KB
bundle/repro/proof/fixed_1.response.headers0.5 KB
bundle/repro/proof/fixed_1.result.txt0.1 KB
bundle/repro/proof/fixed_1.service.before.log4.4 KB
bundle/repro/proof/fixed_1.service.log9.3 KB
bundle/repro/proof/fixed_2.health.after-restart.txt0.0 KB
bundle/repro/proof/fixed_2.health.txt0.0 KB
bundle/repro/proof/fixed_2.identity.txt0.1 KB
bundle/repro/proof/fixed_2.marker.txt0.0 KB
bundle/repro/proof/fixed_2.negative_control.json0.3 KB
bundle/repro/proof/fixed_2.privilege.txt0.1 KB
bundle/repro/proof/fixed_2.request.json0.6 KB
bundle/repro/proof/fixed_2.response.headers0.5 KB
bundle/repro/proof/fixed_2.result.txt0.1 KB
bundle/repro/proof/fixed_2.service.before.log4.4 KB
bundle/repro/proof/fixed_2.service.log9.4 KB
bundle/repro/proof/vulnerable_1.health.after-restart.txt0.0 KB
bundle/repro/proof/vulnerable_1.health.txt0.0 KB
bundle/repro/proof/vulnerable_1.identity.txt0.1 KB
bundle/repro/proof/vulnerable_1.privilege.txt0.1 KB
bundle/repro/proof/vulnerable_1.result.txt0.1 KB
bundle/repro/proof/vulnerable_1.service.before.log4.4 KB
bundle/repro/proof/vulnerable_2.health.after-restart.txt0.0 KB
bundle/repro/proof/vulnerable_2.health.txt0.0 KB
bundle/repro/proof/vulnerable_2.identity.txt0.1 KB
bundle/repro/proof/vulnerable_2.privilege.txt0.1 KB
bundle/repro/proof/vulnerable_2.response.headers0.5 KB
bundle/repro/proof/vulnerable_2.result.txt0.1 KB
bundle/repro/proof/vulnerable_2.service.before.log4.4 KB
bundle/repro/rca_report.md10.3 KB
bundle/repro/reproduction_steps.sh15.4 KB
bundle/repro/runtime_manifest.json7.5 KB
bundle/repro/validation_verdict.json1.5 KB
08 · How to Fix

How to Fix CVE-2026-84647

Coming soon

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

10 · FAQ

FAQ: CVE-2026-84647

Is CVE-2026-84647 exploitable?

Yes. Pruva independently reproduced CVE-2026-84647 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-00349).

How severe is CVE-2026-84647?

CVE-2026-84647 is rated high severity.

What type of vulnerability is CVE-2026-84647?

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

How can I reproduce CVE-2026-84647?

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-84647 reproduction verified?

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

References for CVE-2026-84647

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