← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-53435 · CWE-502 · Disclosed 2026-06-10

In Jenkins 2

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a visitor badge that can turn into the master key for your build factory

CVE-2026-53435 is an unsafe deserialization flaw in Jenkins core affecting weekly releases through 2.567 and LTS through 2.555.2, fixed in 2.568 and 2.555.3. An attacker who can reach the relevant config.xml workflow with the required Jenkins permissions can make Jenkins deserialize unexpected core or plugin types, then reach those objects through Stapler HTTP routing; the documented outcomes include arbitrary file read from the controller, user impersonation, and requests sent as other users up to Script Console access and code execution.

The vendor's HIGH 8.8 is fair if you score only the entry conditions, but too low for real enterprise blast radius. Jenkins is a CI/CD control plane, so successful exploitation is not just 'one app server got popped'—it is a realistic *supply-chain pivot* into signing material, deployment credentials, build secrets, artifacts, and downstream estate.

"Authenticated-on-paper, supply-chain pivot in practice: Jenkins turns this into a critical patch."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Land a Jenkins foothold

The attacker first needs a real Jenkins identity with Overall/Read, or another permission set that reaches a POST config.xml path. In practice this usually means stolen SSO credentials, a compromised developer account, an insider, or an already-established internal foothold using standard HTTP tooling like curl, Burp, or a custom requests script.
Conditions required:
  • Valid Jenkins account or equivalent permissions
  • Target is running Jenkins <=2.567 or LTS <=2.555.2
  • Relevant HTTP endpoints are reachable
Where this breaks in practice:
  • Not anonymous; this is *not* an internet-spray unauthenticated bug
  • MFA, SSO, IP allowlists, and sane RBAC cut off a lot of opportunistic abuse
  • Many Jenkins deployments do not grant broad low-privilege users configuration rights
Detection/coverage: Version scanners can flag affected builds, but most network scanners cannot prove exploitability because the chain is permission-dependent.
STEP 02

Plant a routable deserialized object

Using an attacker-controlled config.xml submission, the attacker coerces Jenkins into deserializing an unexpected but Jenkins-resident type that survives the class filter. Public research from AmesianX shows one concrete path using hudson.Plugin$DummyImpl inside a DescribableList<ViewProperty> so the object persists and becomes reachable through Stapler routing.
Conditions required:
  • A writable config.xml path or other advisory-described authenticated path
  • Knowledge of a Jenkins/core or plugin type that fits the sink
Where this breaks in practice:
  • Generic Java gadget chains do not automatically work because Jenkins filters deserialization to core/plugin-defined classes
  • The exact sink matters; many naive payloads fail
  • Plugin mix and object graph details can change which gadgets are practical
Detection/coverage: Look for unusual POST .../config.xml events, suspicious object persistence in view/job configs, and odd paths in Jenkins access logs after a config update.
STEP 03

Abuse Stapler-exposed behavior

Once the object is stored and routable, the attacker drives it over HTTP to get impact. The public PoC demonstrates arbitrary file read from the controller; the vendor advisory further states the same primitive can be used for user impersonation and sending requests as any user, including to Script Console endpoints.
Conditions required:
  • Deserialized object remains reachable after save/load
  • Controller HTTP routing exposes useful methods or resources
Where this breaks in practice:
  • Some deployments have fewer useful plugins or disabled admin features
  • The public PoC proves file read; full RCE chains may require selecting a better target path or privileged destination
Detection/coverage: Jenkins logs, reverse proxy logs, and EDR on the controller may catch abnormal file access, strange Stapler paths, or impersonated admin actions, but only after the malicious object already exists.
STEP 04

Pivot from controller compromise to supply chain

On a real Jenkins controller, file read and user impersonation usually expose API tokens, SCM credentials, cloud keys, signing secrets, or administrator capability. From there the attacker can tamper with pipelines, poison artifacts, trigger malicious deployments, or run code on agents and downstream systems using native Jenkins features rather than noisy malware.
Conditions required:
  • Jenkins holds meaningful secrets or deployment authority
  • Controller connects to SCM, registries, clouds, package repos, or production environments
Where this breaks in practice:
  • Blast radius is smaller on isolated lab instances with no secrets or prod connectivity
  • Well-segmented agents, short-lived credentials, and secret managers reduce follow-on value
Detection/coverage: Traditional vulnerability scanning stops at 'version vulnerable'; supply-chain abuse is better caught by CI/CD audit trails, artifact signing verification, SCM webhook monitoring, and detections for unusual build or credential use.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo evidence of active exploitation in the sources reviewed; CISA KEV: No, and the Jenkins advisory does not claim live attacks.
Public exploit statusYes. A public GitHub PoC by AmesianX demonstrates authenticated arbitrary file read on vulnerable 2.555.2 and failure on patched 2.555.3; RCE chain details were intentionally withheld.
EPSS0.00368 from the provided intel and VulDB, with VulDB labeling activity as *very low*. That is a threat-likelihood signal, not an impact signal.
KEVNot listed in the CISA Known Exploited Vulnerabilities catalog.
CVSS vector realityAV:N/AC:L/PR:L/UI:N means the *technical* chain is easy once you already have the required Jenkins foothold. The decisive caveat is PR:L: this is post-auth, not anonymous edge smash-and-grab.
Affected versionsJenkins weekly <=2.567; Jenkins LTS <=2.555.2.
Fixed versionsUpgrade to weekly 2.568 or LTS 2.555.3.
Exposure pictureShodan's Jenkins search shows broad public exposure potential, with roughly 46k Jenkins product banners and about 1k pages titled Dashboard [Jenkins] in the surfaced snapshot. That overstates exploitable population because this CVE still needs auth and the right Jenkins permissions.
Disclosure timelineDisclosed 2026-06-10; NVD published 2026-06-10 and shows last modification 2026-06-11.
ReporterReported to Jenkins as SECURITY-3707 by dqh1 through the Jenkins Bug Bounty Program.
04 · The Call

noisgate verdict.

Final Verdict
UPGRADED to CRITICAL (9.1/10)

This lands in CRITICAL because the single decisive factor is the role multiplier — Jenkins is a CI/CD controller, so successful exploitation is a supply-chain pivot, not a single-host incident. The authenticated starting point absolutely adds friction, but it does not break the critical floor when the documented chain can end in controller RCE, artifact tampering, secret theft, and downstream fleet compromise.

HIGH Affected-version and fix-version accuracy
MEDIUM Worst-case exploitation path from advisory-described impersonation to controller RCE
MEDIUM Real-world exposure fraction among all Jenkins installs

Why this verdict

  • Downward pressure — authenticated starting point: Step 1 requires Overall/Read plus a real account or other permission set reaching config.xml. That implies credential theft, insider access, or an earlier foothold; MFA, SSO, and RBAC should stop a large slice of opportunistic internet noise.
  • Downward pressure — exposed population narrows fast: Raw Shodan Jenkins counts are not the exploitable population. You need a vulnerable version, reachable login surface, a valid identity, and a permission model loose enough to hit a workable path; each prerequisite compounds downward pressure on mass exploitation.
  • Upward pressure — exploitability is no longer theoretical: A public PoC exists and demonstrates authenticated arbitrary file read with patched-vs-vulnerable differential validation. That collapses a lot of uncertainty around whether the advisory was merely academic.
  • Role multiplier: On a low-value role like a dev sandbox, the chain may end at one controller and a few test credentials. On a typical role like a shared line-of-business build server, it plausibly ends in host compromise plus theft of SCM, artifact, and deployment credentials. On the high-value canonical role—production CI/CD controller—the documented chain succeeds as a supply-chain pivot, with blast radius from *host* to *fleet* to *downstream software consumers*. Jenkins is itself a CI/CD platform, so this high-value role is common enough to set a CRITICAL floor rather than being a corner case.

Why not higher?

It is not a perfect 10 because the chain is not unauthenticated, not KEV-listed, and not backed by confirmed in-the-wild exploitation. Real attackers still need a valid Jenkins foothold and a permission model that lets them reach a practical deserialization path.

Why not lower?

You cannot responsibly file this under ordinary authenticated app risk because the impact is not bounded to one tenant or one workflow. Once you grant that the advisory's impersonation and Script Console outcomes are plausible on a Jenkins controller, the asset's native role makes this a CI/CD and supply-chain incident class, which floors severity at CRITICAL.

05 · Compensating Control

What to do — in priority order.

  1. Restrict Jenkins exposure — Move controllers behind VPN, SSO-aware reverse proxy, or internal-only access where possible, and remove direct internet reachability for admin and user portals. For a CRITICAL verdict, deploy this compensating control within 3 days to shrink the reachable population while patch scheduling catches up.
  2. Tighten Overall/Read and config permissions — Audit matrix/role permissions and strip broad groups of Overall/Read, View/Configure, Item/Configure, and Agent/Configure unless there is a hard business need. For a CRITICAL verdict, complete the first-pass permission reduction within 3 days because this CVE's exploitability is permission-gated.
  3. Kill stale local users and rotate exposed secrets — Disable dormant Jenkins-local accounts, review SSO group mappings, and rotate any controller-resident secrets that would matter if file read already occurred: API tokens, SCM PATs, cloud keys, signing creds, kubeconfigs, and deployment secrets. Start within 3 days on internet-facing or high-value controllers first.
  4. Instrument config and admin-path logging — Alert on POST requests to config.xml, creation or modification of views/jobs/nodes by low-privilege identities, and any Script Console access. Stand this up within 3 days so you have coverage for attempted exploitation before every node is remediated.
  5. Constrain controller blast radius — Reduce the controller's standing privileges to SCM, cloud, registries, and agents; prefer short-lived credentials from a secrets manager; and verify artifact signing and deployment approvals. Begin within 3 days on production CI/CD because this control limits the supply-chain damage even if one controller is hit.
What doesn't work
  • A generic WAF does not reliably solve this because the exploit lives in authenticated config.xml workflows and legitimate-looking Stapler routes, not a single obvious signatureable payload.
  • Relying on low EPSS alone is the wrong call; EPSS speaks to observed exploitation probability, not the blast radius of a CI/CD controller compromise.
  • Disabling anonymous access only is insufficient because the advisory explicitly allows exploitation with a real user account and Overall/Read.
  • Plugin pruning by itself is incomplete; the flaw is in Jenkins core deserialization and routing behavior, even though plugin-defined types can expand gadget options.
06 · Verification

Crowdsourced verification payload.

Run this on the Jenkins controller or from an auditor workstation that can reach the Jenkins HTTP endpoint. Example invocations: python3 verify_cve_2026_53435.py --url https://jenkins.example.com/ or python3 verify_cve_2026_53435.py --war /usr/share/java/jenkins.war; no admin rights are needed for remote URL checks, but local file checks need read access to the WAR/package path.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# verify_cve_2026_53435.py
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

import argparse
import os
import re
import sys
import zipfile
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError

AFFECTED_WEEKLY_MAX = (2, 567, 0)
AFFECTED_LTS_MAX = (2, 555, 2)
FIXED_WEEKLY = '2.568'
FIXED_LTS = '2.555.3'


def parse_version(v):
    if not v:
        return None
    m = re.search(r'(\d+)\.(\d+)(?:\.(\d+))?', v.strip())
    if not m:
        return None
    return tuple(int(x) if x is not None else 0 for x in m.groups(default='0'))


def classify(vstr):
    vp = parse_version(vstr)
    if not vp:
        return ('UNKNOWN', f'Could not parse version: {vstr!r}')
    if len(vp) == 2:
        vp = (vp[0], vp[1], 0)
    if vp[:2] == (2, 555) and vp <= AFFECTED_LTS_MAX:
        return ('VULNERABLE', f'Jenkins LTS {vstr} <= {FIXED_LTS} fixed threshold')
    if vp <= AFFECTED_WEEKLY_MAX:
        return ('VULNERABLE', f'Jenkins weekly {vstr} <= {FIXED_WEEKLY} fixed threshold')
    if vp >= parse_version(FIXED_LTS) or vp >= parse_version(FIXED_WEEKLY):
        return ('PATCHED', f'Jenkins version {vstr} is newer than affected ranges')
    return ('UNKNOWN', f'Version {vstr} did not cleanly map to weekly/LTS logic')


def version_from_url(base_url, timeout=10):
    base_url = base_url.rstrip('/') + '/login'
    req = Request(base_url, headers={'User-Agent': 'noisgate-cve-check/1.0'})
    with urlopen(req, timeout=timeout) as resp:
        headers = resp.headers
        candidates = [
            headers.get('X-Jenkins'),
            headers.get('X-Hudson'),
        ]
        for c in candidates:
            if c:
                return c.strip(), f'HTTP header from {base_url}'
        body = resp.read(4096).decode('utf-8', errors='ignore')
        m = re.search(r'Jenkins\s+ver\.\s*([0-9][0-9.]+)', body, re.I)
        if m:
            return m.group(1), f'HTML body from {base_url}'
    return None, 'No Jenkins version header/body marker found'


def version_from_war(path):
    with zipfile.ZipFile(path, 'r') as zf:
        for candidate in ['META-INF/MANIFEST.MF', 'WEB-INF/classes/jenkins/model/Jenkins.class']:
            if candidate in zf.namelist():
                break
        manifest = zf.read('META-INF/MANIFEST.MF').decode('utf-8', errors='ignore')
        for line in manifest.splitlines():
            if line.startswith('Jenkins-Version:'):
                return line.split(':', 1)[1].strip(), f'MANIFEST in {path}'
            if line.startswith('Implementation-Version:'):
                return line.split(':', 1)[1].strip(), f'MANIFEST in {path}'
    return None, f'No version found in {path}'


def main():
    ap = argparse.ArgumentParser(description='Check Jenkins for CVE-2026-53435 by version')
    ap.add_argument('--url', help='Base Jenkins URL, e.g. https://jenkins.example.com/')
    ap.add_argument('--war', help='Path to jenkins.war')
    args = ap.parse_args()

    if not args.url and not args.war:
        print('UNKNOWN - provide --url or --war')
        sys.exit(2)

    try:
        if args.url:
            version, source = version_from_url(args.url)
        else:
            if not os.path.exists(args.war):
                print(f'UNKNOWN - WAR not found: {args.war}')
                sys.exit(2)
            version, source = version_from_war(args.war)
    except (HTTPError, URLError, TimeoutError, OSError, zipfile.BadZipFile) as e:
        print(f'UNKNOWN - lookup failed: {e}')
        sys.exit(2)
    except Exception as e:
        print(f'UNKNOWN - unexpected error: {e}')
        sys.exit(2)

    if not version:
        print(f'UNKNOWN - no version detected ({source})')
        sys.exit(2)

    status, reason = classify(version)
    print(f'{status} - detected Jenkins {version} via {source}; {reason}')
    if status == 'PATCHED':
        sys.exit(0)
    if status == 'VULNERABLE':
        sys.exit(1)
    sys.exit(2)


if __name__ == '__main__':
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, treat every Jenkins controller as a CI/CD trust anchor and sort them by blast radius: internet-exposed, production-deploying, artifact-signing, or secret-rich controllers first. Under the noisgate mitigation SLA, apply compensating controls within 3 days—restrict exposure, tighten Overall/Read and config.xml-relevant permissions, disable stale accounts, and turn on logging for config.xml writes and Script Console access—then complete upgrades to 2.568 or 2.555.3 within the noisgate remediation SLA of 90 days, with high-value controllers done first rather than last.

Sources

  1. Jenkins Security Advisory 2026-06-10
  2. NVD CVE-2026-53435
  3. CVE.org record
  4. oss-sec disclosure
  5. Public PoC by AmesianX
  6. CISA Known Exploited Vulnerabilities catalog
  7. VulDB entry with EPSS/KEV snapshot
  8. Shodan Jenkins search snapshot
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.