← Back to Feed CACHED · 2026-10-07 09:59:28 · CACHE_KEY CVE-2026-70426
CVE-2026-70426 · CWE-502 · Disclosed 2026-08-05

Jenkins Remoting JEP-200 Deserialization Filter Bypass via Fallback Class Resolution

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

The lock on the vault door has a second keyhole nobody checked — and every build job already has a key

CVE-2026-70426 is a deserialization filter bypass in the Jenkins Remoting library (versions ≤3384.v60d89463d9e0, except 3355.3357.v931d3c992987), bundled with Jenkins weekly ≤2.575 and LTS ≤2.568.1. Jenkins Remoting serializes Java objects for controller↔agent communication. To prevent gadget-chain attacks, Jenkins enforces the JEP-200 class allowlist during deserialization. However, the Remoting implementation contains a *fallback code path* for resolving classes that never consults the JEP-200 filter. An attacker who can connect as a Jenkins agent, run code on an existing agent, or hold the Agent/Connect permission can send a malicious serialized object through the fallback path, bypassing the allowlist entirely and achieving remote code execution on the Jenkins controller. The exploitable surface is restricted to classes on the Jenkins core classpath that are not on the legacy pre-JEP-200 denylist — plugin dependencies are excluded.

The vendor's CRITICAL / 9.0 rating is broadly justified. The CVSS vector (AV:N/AC:H/PR:N/UI:N/S:C) correctly captures the scope-change from agent to controller and flags high complexity — finding a usable gadget chain on the restricted core classpath is non-trivial. The PR:N component is generous (agent connection secrets or Agent/Connect permission are typically needed), but in the CI/CD threat model this barely matters: build jobs already execute arbitrary code on agents by design. Every PR, every pipeline script, every shared library is code running in the agent context. The attack doesn't require breaking in — it requires escalating *up* from a position the system was designed to give you. Jenkins controllers store source code, deployment credentials, cloud provider secrets, and signing keys. Controller compromise is supply-chain compromise. The vendor severity matches reality.

"JEP-200 bypass lets any build job escalate to controller RCE — your CI/CD crown jewels are one gadget chain away."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Obtain agent-level execution

The attacker needs code running inside a Jenkins agent JVM, or the ability to connect a rogue agent to the controller. In open-source or inner-source Jenkins instances, this is trivially achieved: submit a PR or modify a Jenkinsfile, and the CI system runs your code on an agent. Alternatively, compromise an existing agent host, or connect a new agent if the JNLP port (default TCP/50000) is reachable and the agent secret is weak or leaked.
Conditions required:
  • Network path to Jenkins controller's agent listener (TCP/50000 or WebSocket)
  • Agent secret / JNLP token, OR ability to submit a build that runs on an agent, OR Agent/Connect permission
Where this breaks in practice:
  • Well-managed Jenkins instances restrict agent connections to known subnets and rotate secrets
  • Kubernetes-based agents with ephemeral pods limit persistent agent compromise
  • Organizations that disable the TCP agent port in favor of WebSocket reduce rogue-agent surface
Detection/coverage: Network IDS/firewall logs for unexpected connections to TCP/50000; Jenkins audit log for AgentConnected events from unknown IPs.
STEP 02

Craft a serialized payload targeting the fallback path

The attacker constructs a Java serialized object that resolves through the Remoting fallback class-resolution path rather than the primary path guarded by JEP-200. The payload must use a gadget chain composed exclusively of classes on the Jenkins core classpath (e.g., Guava, args4j, Stapler, Jelly, XStream, or JDK-bundled classes) and must not hit entries on the pre-JEP-200 denylist. Tools like ysoserial or GadgetInspector can enumerate available chains, though custom chain research is likely needed for this restricted classpath.
Conditions required:
  • Knowledge of Jenkins core classpath contents
  • A viable gadget chain that avoids the pre-JEP-200 denylist
  • Understanding of the fallback resolution trigger in Remoting
Where this breaks in practice:
  • No public PoC or known gadget chain has been demonstrated through this path
  • The pre-JEP-200 denylist blocks the most common gadget entry points (Commons Collections transformers, etc.)
  • Plugin dependencies are explicitly excluded, significantly narrowing the gadget surface
Detection/coverage: Java deserialization anomaly detection (e.g., contrast-agent, Nessus plugin for Jenkins version); Remoting channel traffic inspection is not commonly deployed.
STEP 03

Send the payload over the Remoting channel

The crafted serialized object is transmitted from the agent to the controller over the Remoting channel (JNLP4 protocol or WebSocket). The Remoting library on the controller deserializes the object. When the fallback class-resolution path is triggered, the JEP-200 filter is bypassed, and the gadget chain executes in the controller JVM's security context.
Conditions required:
  • Active Remoting channel between attacker-controlled agent and controller
  • Payload triggers the fallback resolution path specifically
Where this breaks in practice:
  • Remoting protocol is binary and not trivially injectable — requires control of an actual agent process or a compatible client
  • Agent-to-controller security hardening (if enabled) may restrict certain callable types
Detection/coverage: Jenkins agent protocol monitoring is rare in production; no standard SIEM signature exists for this specific bypass. Version-based detection (checking Jenkins/Remoting version) is the primary scanner approach.
STEP 04

Achieve RCE on the Jenkins controller

The gadget chain executes arbitrary code in the Jenkins controller process, typically running as a service account with broad filesystem and network access. The attacker can now read the Jenkins credential store (credentials.xml, secrets/ directory), access all configured SCM repositories, modify build pipelines, inject backdoors into artifacts, pivot to production deployment targets, or exfiltrate secrets stored in Jenkins' encrypted credential store.
Conditions required:
  • Successful gadget chain execution on controller JVM
Where this breaks in practice:
  • Jenkins controller hardened with minimal OS privileges limits post-exploitation lateral movement
  • Secrets stored in external vaults (HashiCorp Vault, AWS Secrets Manager) rather than Jenkins credential store reduce blast radius
Detection/coverage: EDR on the controller host detecting anomalous child processes (e.g., java spawning bash/cmd); file integrity monitoring on $JENKINS_HOME/secrets/; anomalous outbound connections from the controller.
03 · Compensating Control

1
CRITICAL 8.8→LOW 2.0
SEVERITY REDUCED
Apply the Jenkins CERT SECURITY-3911-3930 workaround plugin immediately — Jenkins published a workaround plugin that patches the fallback deserialization path without requiring a full Jenkins upgrade. Deploy within the noisgate mitigation SLA of ≤3 days for CRITICAL findings. This directly closes the vulnerable code path and is the fastest compensating control while you schedule the full upgrade.
2
CRITICAL 8.8→HIGH 7.5
SEVERITY REDUCED
Restrict Agent/Connect permission to dedicated service accounts with strong secrets — Audit your Jenkins authorization strategy and ensure Agent/Connect is granted only to machine identities with rotated JNLP secrets. Remove this permission from human accounts and from 'authenticated' group defaults. This narrows the 'rogue agent connection' vector but does NOT prevent exploitation from code already running on legitimate agents. Deploy within 3 days.
3
CRITICAL 8.8→HIGH 8.0
SEVERITY REDUCED
Firewall the JNLP agent listener (TCP/50000) to known agent subnets only — Block inbound connections to the Jenkins agent listener from any network segment that does not host authorized build agents. This prevents external or lateral rogue-agent connections but does not mitigate exploitation from code running on already-connected legitimate agents. Deploy within 3 days.
4
CRITICAL 8.8→HIGH 7.0
SEVERITY REDUCED
Move secrets to an external vault with just-in-time injection — Migrate credentials from Jenkins' built-in credential store to HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault using the appropriate Jenkins plugin. Configure short-lived, scoped tokens injected at build time. This does not prevent controller RCE but drastically reduces the blast radius of credential theft post-exploitation. Deploy within 30 days as a structural improvement.
5
CRITICAL 8.8→CRITICAL 8.5
Deploy EDR on the Jenkins controller host with process-tree monitoring — Ensure endpoint detection and response coverage on the controller. Alert on the Jenkins Java process spawning unexpected child processes (bash, cmd.exe, powershell, curl, wget). This is a detection-only control — it does not prevent exploitation but shortens attacker dwell time. Deploy within 3 days.
What doesn't work
  • WAF / reverse proxy in front of the Jenkins web UI — The vulnerability is in the Remoting binary protocol (JNLP4/WebSocket agent channel), not in the HTTP API. A WAF inspecting HTTP traffic will not see or block the malicious serialized payload.
  • Jenkins CSRF protection / API token enforcement — These protect the HTTP API surface. The Remoting channel is a separate protocol with its own authentication (agent secrets). CSRF tokens are irrelevant to agent↔controller communication.
  • Disabling the Script Console — While a good hardening measure, the Script Console is an HTTP-based feature. This vulnerability operates entirely over the Remoting channel and does not use the Script Console.
  • Updating plugins only — The vulnerability is in Jenkins core's bundled Remoting library. Plugin updates do not change the Remoting version. A core/LTS upgrade or the dedicated workaround plugin is required.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNone observed. Not listed in CISA KEV. No campaigns documented by Mandiant, CrowdStrike, or Proofpoint as of 2026-10-07.
Proof-of-ConceptNo public PoC. No repositories found on GitHub named after CVE-2026-70426. No entries on pocindex.io, ExploitDB, or Nuclei templates. The restricted core-classpath gadget surface makes weaponization non-trivial but not impossible for skilled researchers.
EPSS0.454% (37th percentile) — low exploitation probability in the next 30 days, reflecting absence of public tooling.
CISA KEVNot listed as of 2026-10-07.
CVSS VectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H — 9.0 CRITICAL. Scope-change (S:C) reflects agent→controller escalation. AC:H reflects gadget-chain complexity. PR:N is generous; real-world exploitation requires agent-level access.
Affected VersionsJenkins weekly ≤2.575, LTS ≤2.568.1, Remoting ≤3384.v60d89463d9e0 (except 3355.3357.v931d3c992987).
Fixed VersionsJenkins 2.576 (weekly), LTS 2.568.2. Remoting fix included in both. Standalone Remoting: 3385.vf1123fb_515da_ or later.
Internet ExposureShodan reports ~1,500–1,600 Jenkins controllers with dashboards exposed; historically up to 78,000 with http.title:"Jenkins". JNLP port 50000 is exposed on Docker deployments by default. Most enterprise controllers are internal-only, but the agent connection surface (TCP/50000 or WebSocket) is the relevant attack surface here.
Disclosure & ReporterDisclosed 2026-08-05 via Jenkins Security Advisory. SECURITY-3911. Reported through the European Commission's Jenkins Bug Bounty Program. Part of an advisory batch covering 21 CVEs (CVE-2026-70426 through CVE-2026-70448).
WorkaroundJenkins CERT published a mitigation repository for environments that cannot patch immediately.

Sources.

  1. Jenkins Security Advisory 2026-08-05
  2. GHSA-v269-8r2r-vj93 — GitHub Security Advisory
  3. Jenkins CERT Workaround — SECURITY-3911-3930
  4. GBHackers — Critical Jenkins Deserialization Flaw Analysis
  5. CyberSecurityNews — Jenkins Code Execution Vulnerability
  6. Feedly CVE Intelligence — CVE-2026-70426
  7. SentinelOne Vulnerability Database — CVE-2026-70426
  8. Jenkins Exposed Services Documentation
05 · The Call

Final Verdict
= UNCHANGED to CRITICAL (8.8/10)

Why this verdict

  • Canonical CI/CD component — floor is CRITICAL. Jenkins controllers are *definitionally* CI/CD infrastructure. 100% of Jenkins installations serve the high-value CI/CD role. A compromised controller yields access to source code, deployment credentials, signing keys, and artifact pipelines — supply-chain-scale blast radius. Per the deployment-role floor rule, the verdict cannot drop below CRITICAL.
  • Agent-level access is the normal operating mode, not a barrier. The CVSS vector marks PR:N, and while that's debatable, the practical reality is even stricter: CI/CD systems are *designed* to run developer-submitted code on agents. Every PR build, every pipeline script, every shared library is attacker-controlled code already executing in the agent context. The 'prerequisite' is the system working as intended.
  • Role multiplier: CI/CD controller. The documented chain succeeds whenever code runs on a connected agent — this is the standard deployment model. Blast radius on success: controller RCE → credential store theft → SCM access → artifact tampering → supply-chain compromise. This is fleet-to-supply-chain impact. No role in the Jenkins ecosystem is low-value; the controller IS the high-value target.
  • AC:H and restricted gadget surface justify the 0.2-point reduction, not more. The gadget chain must use only Jenkins core classpath classes and avoid the pre-JEP-200 denylist. Plugin dependencies are excluded. No public PoC exists. EPSS is 0.454%. These factors reduce *immediacy* but do not reduce *severity* — a skilled researcher or nation-state actor can invest the time to find a chain.
  • Role multiplier: identity and secrets store. Jenkins credential stores frequently hold SSH keys, API tokens, cloud IAM credentials, and database passwords. Controller compromise is functionally equivalent to a PAM breach in many organizations. This reinforces the CRITICAL floor.

Why not higher?

The vendor already assigned the maximum reasonable score for an AC:H vector (9.0). The scope-change, full CIA impact, and network vector are all accurately captured. A 10.0 would require AC:L and trivial exploitation, which this vulnerability does not offer — the restricted gadget surface and absence of a public chain are real complexity barriers.

Why not lower?

Jenkins is a canonical CI/CD component where 100% of installs occupy the high-value role. The deployment-role floor rule mandates CRITICAL when the chain succeeds with supply-chain impact, which it does for any installation where agents run build code (i.e., virtually all of them). The lack of a public PoC reduces *urgency* but not *severity* — the vulnerability class (Java deserialization filter bypass) is well-understood, and history shows that JEP-200 bypasses are consistently weaponized within months of disclosure (cf. CVE-2017-1000353, CVE-2024-43044).

06 · Verification

Crowdsourced verification payload.

Run this script on each Jenkins controller host (or remotely via SSH). It checks the installed Jenkins version and the bundled Remoting library version. Requires read access to $JENKINS_HOME or the Jenkins WAR file. Invoke as: sudo bash check_cve_2026_70426.sh /var/lib/jenkins (pass the JENKINS_HOME path as the first argument).

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-70426 Checker — Jenkins Remoting JEP-200 Deserialization Filter Bypass
# Usage: bash check_cve_2026_70426.sh /var/lib/jenkins
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -euo pipefail

JENKINS_HOME="${1:-/var/lib/jenkins}"
RESULT="UNKNOWN"

# Try to read Jenkins version from identity.xml or config
get_jenkins_version() {
  local id_file="$JENKINS_HOME/config.xml"
  if [ -f "$JENKINS_HOME/identity.xml.bak" ] || [ -f "$id_file" ]; then
    # Check war manifest
    local war_paths=("/usr/share/java/jenkins.war" "/usr/lib/jenkins/jenkins.war" "$JENKINS_HOME/jenkins.war")
    for wp in "${war_paths[@]}"; do
      if [ -f "$wp" ]; then
        unzip -p "$wp" META-INF/MANIFEST.MF 2>/dev/null | grep -i 'Jenkins-Version' | awk -F': ' '{print $2}' | tr -d '\r'
        return
      fi
    done
  fi
  # Fallback: check via CLI or HTTP
  if command -v jenkins-cli &>/dev/null; then
    jenkins-cli version 2>/dev/null
    return
  fi
  # Fallback: parse from update center metadata
  if [ -f "$JENKINS_HOME/updates/default.json" ]; then
    python3 -c "import json,sys; d=json.load(open('$JENKINS_HOME/updates/default.json')); print(d.get('core',{}).get('version',''))" 2>/dev/null
    return
  fi
  echo ""
}

# Check Remoting version from the jar
get_remoting_version() {
  local remoting_jar="$JENKINS_HOME/war/WEB-INF/lib/remoting-*.jar"
  # Expand glob
  for jar in $remoting_jar; do
    if [ -f "$jar" ]; then
      unzip -p "$jar" META-INF/MANIFEST.MF 2>/dev/null | grep -i 'Implementation-Version\|Bundle-Version' | head -1 | awk -F': ' '{print $2}' | tr -d '\r'
      return
    fi
  done
  # Try extracted war directory
  local war_paths=("/usr/share/java/jenkins.war" "/usr/lib/jenkins/jenkins.war")
  for wp in "${war_paths[@]}"; do
    if [ -f "$wp" ]; then
      unzip -l "$wp" 2>/dev/null | grep 'remoting-' | awk '{print $NF}' | sed 's/.*remoting-//;s/\.jar//'
      return
    fi
  done
  echo ""
}

# Version comparison: returns 0 if $1 >= $2
version_gte() {
  [ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" = "$2" ]
}

echo "=== CVE-2026-70426 Check ==="
echo "Jenkins Home: $JENKINS_HOME"

JENKINS_VER=$(get_jenkins_version)
REMOTING_VER=$(get_remoting_version)

echo "Jenkins Version: ${JENKINS_VER:-not detected}"
echo "Remoting Version: ${REMOTING_VER:-not detected}"

# Check for workaround plugin
WORKAROUND_INSTALLED=false
if [ -d "$JENKINS_HOME/plugins" ]; then
  if ls "$JENKINS_HOME/plugins/" 2>/dev/null | grep -qi 'SECURITY-3911\|security-3911'; then
    WORKAROUND_INSTALLED=true
    echo "Workaround plugin: INSTALLED"
  fi
fi

if [ -z "$JENKINS_VER" ] && [ -z "$REMOTING_VER" ]; then
  echo "Result: UNKNOWN — could not determine Jenkins or Remoting version."
  echo "Verify manually: Manage Jenkins > About Jenkins, or check /api/json on the controller."
  exit 2
fi

# Fixed versions: Jenkins 2.576+, LTS 2.568.2+
# Remoting fixed: 3385+ (or the exception 3355.3357.v931d3c992987)
if [ -n "$JENKINS_VER" ]; then
  # Check if it's an LTS version (x.y.z format)
  if echo "$JENKINS_VER" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
    # LTS — fixed in 2.568.2
    if version_gte "$JENKINS_VER" "2.568.2"; then
      RESULT="PATCHED"
    else
      RESULT="VULNERABLE"
    fi
  else
    # Weekly — fixed in 2.576
    if version_gte "$JENKINS_VER" "2.576"; then
      RESULT="PATCHED"
    else
      RESULT="VULNERABLE"
    fi
  fi
fi

# Override if workaround plugin is installed
if [ "$WORKAROUND_INSTALLED" = true ] && [ "$RESULT" = "VULNERABLE" ]; then
  RESULT="PATCHED"
  echo "Note: Workaround plugin detected — fallback path is mitigated."
fi

echo "Result: $RESULT"
case "$RESULT" in
  PATCHED)    exit 0 ;;
  VULNERABLE) exit 1 ;;
  *)          exit 2 ;;
esac