Back to Articles

Inside Jenkins Attack Framework: How Accenture's Red Team Exploits CI/CD Infrastructure

[ View on GitHub ]

Inside Jenkins Attack Framework: How Accenture's Red Team Exploits CI/CD Infrastructure

Hook

A single misconfigured Jenkins server can expose every secret, credential, and deployment key in your entire CI/CD pipeline—and Jenkins Attack Framework makes harvesting them trivial.

Context

Jenkins powers CI/CD pipelines at thousands of enterprises, managing builds, deployments, and—critically—storing credentials for every system it touches: cloud providers, databases, production servers, and container registries. This concentration of secrets makes Jenkins an irresistible target for attackers. Yet most security tools focus on finding CVEs, not on post-exploitation: what happens after an attacker gains that initial foothold, whether through stolen credentials, misconfigured anonymous access, or social engineering.

Accenture's Cyber Range team built Jenkins Attack Framework to fill this gap during offensive security engagements. Traditional penetration testing tools like Metasploit include basic Jenkins exploit modules, but they don't address the unique attack surface Jenkins presents: the Groovy Script Console that enables arbitrary code execution, build job logs that leak credentials in plain text, and the distributed agent architecture that provides lateral movement opportunities. JAF codifies real-world attack patterns from professional red team operations into a purpose-built toolkit that covers reconnaissance, credential harvesting, command execution, and persistence—all optimized for Jenkins' specific APIs and quirks.

Technical Insight

Jenkins Attack Framework's architecture reveals sophisticated understanding of Jenkins internals. At its core, JAF is a Python CLI tool with modular commands that map to different phases of an engagement. Each command encapsulates API interactions, handles Jenkins' authentication quirks, and parses responses to extract actionable intelligence.

The authentication layer demonstrates this sophistication. Jenkins supports multiple authentication schemes—basic auth, API tokens, federated SSO with cookies, and CSRF protection via Crumb tokens. JAF handles all of them:

# Example of how JAF structures authentication
jaf.py --url https://jenkins.corp.com \
  --username admin \
  --password-file creds.txt \
  --use-crumb \
  DumpCreds

# Or using cookie-based federation auth
jaf.py --url https://jenkins.corp.com \
  --cookie "JSESSIONID=ABC123; auth_token=XYZ" \
  --use-crumb \
  ListJobs

The --use-crumb flag addresses Jenkins' CSRF protection, which requires clients to request a crumb token before making state-changing requests. JAF automatically fetches and includes this token in subsequent requests, handling a detail that would trip up manual exploitation attempts.

The credential dumping commands showcase JAF's understanding of where secrets hide in Jenkins. The DumpCreds command hits the /credentials/store/system/domain/_/api/json endpoint to enumerate stored credentials, but it only retrieves metadata—Jenkins (correctly) doesn't expose credential values via API. The more powerful DumpCredsViaJob command works around this by creating a temporary build job that executes Groovy script to access Jenkins' credential store programmatically:

// JAF injects Groovy like this to extract credentials
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.domains.*

def creds = CredentialsProvider.lookupCredentials(
  Credentials.class,
  Jenkins.instance,
  null,
  null
)

creds.each { c ->
  if (c instanceof UsernamePasswordCredentials) {
    println "Username: ${c.username}"
    println "Password: ${c.password}"
  }
}

This approach exploits Jenkins' design: build jobs run with elevated privileges and can access the entire credential store through Jenkins' internal API. JAF creates the job, triggers a build, captures the output, then deletes the job—all automated in a single command.

The ghost job feature represents JAF's most advanced capability. Traditional persistent jobs appear in the Jenkins UI, alerting administrators to suspicious activity. Ghost jobs exploit a timing window: they appear in the UI during creation, but JAF includes a PowerShell payload that immediately renames the job's workspace directory on the Windows slave. When Jenkins tries to update the job status, it can't find the directory and assumes the job doesn't exist, removing it from the UI—but the payload continues executing:

# Simplified logic of ghost job implementation
1. Create job on Windows slave with malicious payload
2. Payload first action: Rename C:\Jenkins\workspace\jobname to random string
3. Jenkins loses reference to job (404 on workspace path)
4. UI no longer displays job, but process continues running
5. Attacker maintains persistent access without UI evidence

This requires pre-compiling a C++ helper binary that handles the directory operations, adding operational complexity but delivering powerful stealth capabilities.

JAF's threading implementation allows parallel operations across multiple Jenkins instances or jobs. The --threads flag enables concurrent credential dumping across hundreds of build jobs simultaneously, dramatically reducing engagement time. This reveals JAF's design for enterprise-scale Jenkins deployments where a single server might have thousands of jobs, each potentially containing leaked credentials in console output or environment variables.

Gotcha

Jenkins Attack Framework is explicitly a post-exploitation tool, not an initial access toolkit. You need credentials, API tokens, or anonymous access before JAF becomes useful. It won't brute-force passwords, scan for CVEs, or exploit authentication bypasses. If you're starting from zero access, you'll need to chain JAF with other tools or techniques to gain that initial foothold.

The AccessCheck command's false positive warnings deserve attention. Jenkins' permission model is Byzantine—permissions inherit through folder hierarchies, can be overridden per-job, and interact unpredictably with plugins. JAF's heuristics for detecting what your compromised account can access are educated guesses based on API responses, but they may flag capabilities you can't actually exercise. Always validate detected permissions manually before building attack plans on them. The ghost job feature also has sharp edges: it only works on Windows slaves, requires compiling C++ code with Visual Studio beforehand, and can leave orphaned processes if something goes wrong during the directory rename. It's powerful but finicky, demanding careful setup and testing in a lab environment before operational use.

Verdict

Use if: You're conducting authorized red team operations or penetration tests against Jenkins infrastructure with at least minimal access (credentials, API tokens, or anonymous read), need to demonstrate the risk of compromised Jenkins credentials during security assessments, or want to automate credential harvesting and lateral movement in large-scale Jenkins deployments. JAF excels at post-exploitation activities and turning limited Jenkins access into full infrastructure compromise.

Skip if: You lack initial access to target Jenkins instances, need a general-purpose vulnerability scanner (use OWASP Dependency-Check or Jenkins Security Scan instead), want to test Jenkins security from a defensive posture (use Jenkins Configuration as Code and Jenkins Audit Log plugin instead), or aren't comfortable with the legal and ethical implications of offensive security tools. This is a specialized exploitation framework for authorized security professionals, not a development or hardening tool.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/accenture-jenkins-attack-framework.svg)](https://starlog.is/api/badge-click/developer-tools/accenture-jenkins-attack-framework)