VYPR
Critical severityNVD Advisory· Published Mar 28, 2019· Updated Aug 5, 2024

CVE-2019-1003041

CVE-2019-1003041

Description

A sandbox bypass vulnerability in Jenkins Pipeline: Groovy Plugin 2.64 and earlier allows attackers to invoke arbitrary constructors in sandboxed scripts.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Jenkins Pipeline: Groovy Plugin 2.64 and earlier allows sandbox bypass through type casts, enabling arbitrary constructor invocation.

Vulnerability

A sandbox bypass vulnerability exists in Jenkins Pipeline: Groovy Plugin (workflow-cps) version 2.64 and earlier. The sandbox protection could be circumvented through methods supporting type casts and type coercion, allowing attackers to invoke constructors for arbitrary types. This affects the plugin's handling of Groovy scripts compiled to WorkflowScript class, where type casting operations (e.g. (Jenkins as I).instance) could bypass the script security sandbox restrictions [1][2].

Exploitation

An attacker with the ability to define and execute Pipeline scripts in a Jenkins instance (e.g., with Job/Configure permission or access to Jenkinsfile in a multibranch pipeline) can craft a Groovy script that exploits type casting or type coercion to invoke constructors that would normally be blocked by the sandbox. The attacker does not need authentication to Jenkins if they can already run scripts, but must be able to write or modify Pipeline definitions. The attack involves using Groovy's type cast syntax (e.g., casting an object to an interface with a method that returns a restricted class instance) to bypass the sandbox’s rejection of static method calls like Jenkins.getInstance() [1].

Impact

Successful exploitation allows the attacker to invoke arbitrary constructors in the sandboxed script context, effectively bypassing the script security sandbox. This can lead to remote code execution (RCE) within the Jenkins controller process, enabling full compromise of the Jenkins server and access to all managed nodes, credentials, and builds [2].

Mitigation

Jenkins released Pipeline: Groovy Plugin version 2.65 which hardens the plugin to prevent type cast and type coercion bypasses. The fix is included in the Jenkins Security Advisory 2019-03-25. Users should upgrade to version 2.65 or later immediately. No workaround is available for older versions [2][4].

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.jenkins-ci.plugins.workflow:workflow-cpsMaven
< 2.652.65

Affected products

2

Patches

1
2e5a67fde9ba

[SECURITY-1353] Problems with casts

3 files changed · +92 25
  • pom.xml+2 2 modified
    @@ -70,7 +70,7 @@
             <git-plugin.version>3.1.0</git-plugin.version>
             <workflow-support-plugin.version>3.2</workflow-support-plugin.version>
             <scm-api-plugin.version>2.2.6</scm-api-plugin.version>
    -        <groovy-cps.version>1.25</groovy-cps.version>
    +        <groovy-cps.version>1.26</groovy-cps.version>
             <structs-plugin.version>1.17</structs-plugin.version>
         </properties>
         <dependencies>
    @@ -97,7 +97,7 @@
             <dependency>
                 <groupId>org.jenkins-ci.plugins</groupId>
                 <artifactId>script-security</artifactId>
    -            <version>1.50</version>
    +            <version>1.56</version>
             </dependency>
             <dependency>
                 <groupId>org.jenkins-ci.plugins</groupId>
    
  • src/main/java/org/jenkinsci/plugins/workflow/cps/CpsWhitelist.java+13 0 modified
    @@ -19,6 +19,8 @@
     import java.util.logging.Level;
     import java.util.logging.Logger;
     import jenkins.model.Jenkins;
    +import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
    +import org.kohsuke.groovy.sandbox.impl.Checker;
     
     /**
      * {@link Whitelist} implementation for CPS flow execution.
    @@ -94,6 +96,17 @@ public boolean permitsStaticMethod(Method method, Object[] args) {
             String n = method.getName();
             // type coercive cast. In particular, this is used to build GString. See com.cloudbees.groovy.cps.Builder.gstring
             if (c == ScriptBytecodeAdapter.class && n.equals("asType")) {
    +            Object object = args[0];
    +            Class<?> type = (Class<?>) args[1];
    +            try {
    +                Checker.preCheckedCast(type, object, true, true, false);
    +            } catch (RuntimeException x) {
    +                throw x;
    +            } catch (Error x) {
    +                throw x;
    +            } catch (Throwable x) {
    +                throw new RuntimeException(x);
    +            }
                 return true;
             }
     
    
  • src/test/java/org/jenkinsci/plugins/workflow/cps/CpsFlowDefinition2Test.java+77 23 modified
    @@ -51,6 +51,7 @@
     import org.junit.Ignore;
     import org.junit.Rule;
     import org.junit.Test;
    +import org.junit.rules.ErrorCollector;
     import org.jvnet.hudson.test.BuildWatcher;
     import org.jvnet.hudson.test.Issue;
     import org.jvnet.hudson.test.JenkinsRule;
    @@ -61,6 +62,7 @@ public class CpsFlowDefinition2Test extends AbstractCpsFlowTest {
     
         @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher();
         @Rule public LoggerRule logging = new LoggerRule();
    +    @Rule public ErrorCollector errors = new ErrorCollector();
     
         /**
          * I should be able to have DSL call into async step and then bring it to the completion.
    @@ -282,35 +284,87 @@ public void traitsSandbox() throws Exception {
         @Test public void typeCoercion() throws Exception {
             logging.record(CpsTransformer.class, Level.FINEST);
             WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p");
    -        job.setDefinition(new CpsFlowDefinition("interface I {Object getInstance()}; println((Jenkins as I).instance)", true));
    -        WorkflowRun b = job.scheduleBuild2(0).get();
    -        assertNull(jenkins.jenkins.getSystemMessage());
    -        jenkins.assertBuildStatus(Result.FAILURE, b);
    -        jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", b);
    +        errors.checkSucceeds(() -> {
    +            job.setDefinition(new CpsFlowDefinition("interface I {Object getInstance()}; println((Jenkins as I).instance)", true));
    +            WorkflowRun b = job.scheduleBuild2(0).get();
    +            assertNull(jenkins.jenkins.getSystemMessage());
    +            jenkins.assertBuildStatus(Result.FAILURE, b);
    +            jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", b);
    +            return null;
    +        });
             // Not really the same but just checking:
    -        job.setDefinition(new CpsFlowDefinition("interface I {Object getInstance()}; I i = {Jenkins.instance}; println(i.instance)", true));
    -        b = job.scheduleBuild2(0).get();
    -        assertNull(jenkins.jenkins.getSystemMessage());
    -        jenkins.assertBuildStatus(Result.FAILURE, b);
    -        jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", b);
    -    }
    -
    -    @Issue("SECURITY-580")
    +        errors.checkSucceeds(() -> {
    +            job.setDefinition(new CpsFlowDefinition("interface I {Object getInstance()}; I i = {Jenkins.instance}; println(i.instance)", true));
    +            WorkflowRun b = job.scheduleBuild2(0).get();
    +            assertNull(jenkins.jenkins.getSystemMessage());
    +            jenkins.assertBuildStatus(Result.FAILURE, b);
    +            jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", b);
    +            return null;
    +        });
    +        // Some safe idioms:
    +        errors.checkSucceeds(() -> {
    +            job.setDefinition(new CpsFlowDefinition("def x = (double) Math.max(2, 3); echo(/max is $x/)", true));
    +            jenkins.assertLogContains("max is 3", jenkins.buildAndAssertSuccess(job));
    +            return null;
    +        });
    +        errors.checkSucceeds(() -> {
    +            job.setDefinition(new CpsFlowDefinition("def x = Math.max(2, 3) as double; echo(/max is $x/)", true));
    +            jenkins.assertLogContains("max is 3", jenkins.buildAndAssertSuccess(job));
    +            return null;
    +        });
    +        errors.checkSucceeds(() -> {
    +            job.setDefinition(new CpsFlowDefinition("double x = Math.max(2, 3); echo(/max is $x/)", true));
    +            jenkins.assertLogContains("max is 3", jenkins.buildAndAssertSuccess(job));
    +            return null;
    +        });
    +    }
    +
    +    @Issue({"SECURITY-580", "SECURITY-1353"})
         @Test public void positionalConstructors() throws Exception {
             logging.record(CpsTransformer.class, Level.FINEST);
             WorkflowJob p = jenkins.jenkins.createProject(WorkflowJob.class, "p");
             // Control cases:
    -        p.setDefinition(new CpsFlowDefinition("def u = ['http://nowhere.net/'] as URL; echo(/$u/)", true));
    -        jenkins.buildAndAssertSuccess(p);
    -        p.setDefinition(new CpsFlowDefinition("URL u = ['http://nowhere.net/']; echo(/$u/)", true));
    -        jenkins.buildAndAssertSuccess(p);
    -        p.setDefinition(new CpsFlowDefinition("def f = new File('/tmp'); echo(/$f/)", true));
    -        jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String", jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)));
    +        errors.checkSucceeds(() -> {
    +            p.setDefinition(new CpsFlowDefinition("def u = ['http://nowhere.net/'] as URL; echo(/$u/)", true));
    +            jenkins.buildAndAssertSuccess(p);
    +            return null;
    +        });
    +        errors.checkSucceeds(() -> {
    +            p.setDefinition(new CpsFlowDefinition("URL u = ['http://nowhere.net/']; echo(/$u/)", true));
    +            jenkins.buildAndAssertSuccess(p);
    +            return null;
    +        });
    +        errors.checkSucceeds(() -> {
    +            p.setDefinition(new CpsFlowDefinition("def f = new File('/tmp'); echo(/$f/)", true));
    +            jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String", jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)));
    +            return null;
    +        });
             // Test cases:
    -        p.setDefinition(new CpsFlowDefinition("def f = ['/tmp'] as File; echo(/$f/)", true));
    -        jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String", jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)));
    -        p.setDefinition(new CpsFlowDefinition("File f = ['/tmp']; echo(/$f/)", true));
    -        jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String", jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)));
    +        errors.checkSucceeds(() -> {
    +            p.setDefinition(new CpsFlowDefinition("def f = ['/tmp'] as File; echo(/$f/)", true));
    +            jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String", jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)));
    +            return null;
    +        });
    +        errors.checkSucceeds(() -> {
    +            p.setDefinition(new CpsFlowDefinition("File f = ['/tmp']; echo(/$f/)", true));
    +            jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String", jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)));
    +            return null;
    +        });
    +        errors.checkSucceeds(() -> {
    +            p.setDefinition(new CpsFlowDefinition("def f = org.codehaus.groovy.runtime.ScriptBytecodeAdapter.asType(['/tmp'], File); echo(/$f/)", true));
    +            jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String", jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)));
    +            return null;
    +        });
    +        errors.checkSucceeds(() -> {
    +            p.setDefinition(new CpsFlowDefinition("def f = org.codehaus.groovy.runtime.ScriptBytecodeAdapter.castToType(['/tmp'], File); echo(/$f/)", true));
    +            jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod org.codehaus.groovy.runtime.ScriptBytecodeAdapter castToType java.lang.Object java.lang.Class", jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)));
    +            return null;
    +        });
    +        errors.checkSucceeds(() -> {
    +            p.setDefinition(new CpsFlowDefinition("def f = org.kohsuke.groovy.sandbox.impl.Checker.checkedCast(File, ['/tmp'], true, false, false); echo(/$f/)", true));
    +            jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String", jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)));
    +            return null;
    +        });
         }
     
         @Issue("SECURITY-567")
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.