VYPR
Moderate severityNVD Advisory· Published Jul 31, 2019· Updated Aug 4, 2024

CVE-2019-10357

CVE-2019-10357

Description

A missing permission check in Jenkins Pipeline: Shared Groovy Libraries Plugin 2.14 and earlier allowed users with Overall/Read access to obtain limited information about the content of SCM repositories referenced by global libraries.

AI Insight

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

Missing permission check in Jenkins Pipeline: Shared Groovy Libraries Plugin 2.14 and earlier allows users with Overall/Read to discover SCM repository content.

CVE-2019-10357 is a medium-severity vulnerability in the Jenkins Pipeline: Shared Groovy Libraries Plugin (workflow-cps-global-lib) versions 2.14 and earlier. The plugin fails to perform a permission check when processing form validation for the revision parameter (e.g., commit, tag, or branch name) specified for a global library. This bypasses the intended access control, allowing any authenticated user with the Overall/Read permission to query the plugin for information about the content of SCM repositories referenced by those global libraries [1][2].

The attack surface is limited to authenticated Jenkins users who have been granted the Overall/Read permission, which is typically the broadest base permission in a Jenkins instance. The vulnerability exists in the form validation endpoint that does not verify whether the user has the necessary permissions (such as Job/Configure or Library/Configure) to actually modify or view library configuration. As a result, an attacker can send crafted requests to this endpoint to probe the SCM repository [2].

Exploitation allows an attacker to obtain limited information about the content of SCM repositories referenced by global libraries. This could include discovering branch names, tags, or commit hashes that exist in the repository, potentially revealing sensitive project metadata or existence of certain code branches. The vulnerability does not allow code execution or direct modification of the repository content [1].

The issue is fixed in Pipeline: Shared Groovy Libraries Plugin version 2.15, which was released on the same day as the advisory. Users are strongly advised to update to the latest version. The Jenkins Security Advisory 2019-07-31 also announced other vulnerabilities in related plugins, but CVE-2019-10357 is specific to the missing permission check [1][3].

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-cps-global-libMaven
< 2.152.15

Affected products

2

Patches

1
6fce1e241d82

[SECURITY-1422] Add permission checks and CSRF protection to doCheckDefaultVersions

7 files changed · +100 9
  • src/main/java/org/jenkinsci/plugins/workflow/libs/FolderLibraries.java+11 7 modified
    @@ -28,6 +28,7 @@
     import com.cloudbees.hudson.plugins.folder.AbstractFolderProperty;
     import com.cloudbees.hudson.plugins.folder.AbstractFolderPropertyDescriptor;
     import hudson.Extension;
    +import hudson.model.Item;
     import hudson.model.ItemGroup;
     import hudson.model.Job;
     import java.util.ArrayList;
    @@ -69,27 +70,30 @@ public List<LibraryConfiguration> getLibraries() {
                 return false;
             }
     
    -        private Collection<LibraryConfiguration> forGroup(@CheckForNull ItemGroup<?> group) {
    +        private Collection<LibraryConfiguration> forGroup(@CheckForNull ItemGroup<?> group, boolean checkPermission) {
                 List<LibraryConfiguration> libraries = new ArrayList<>();
                 for (ItemGroup<?> g = group; g instanceof AbstractFolder; g = ((AbstractFolder) g).getParent()) {
    -                FolderLibraries prop = ((AbstractFolder<?>) g).getProperties().get(FolderLibraries.class);
    -                if (prop != null) {
    -                    libraries.addAll(prop.getLibraries());
    +                AbstractFolder<?> f = (AbstractFolder<?>) g;
    +                if (!checkPermission || f.hasPermission(Item.CONFIGURE)) {
    +                    FolderLibraries prop = f.getProperties().get(FolderLibraries.class);
    +                    if (prop != null) {
    +                        libraries.addAll(prop.getLibraries());
    +                    }
                     }
                 }
                 return libraries;
             }
     
             @Override public Collection<LibraryConfiguration> forJob(Job<?,?> job, Map<String,String> libraryVersions) {
    -            return forGroup(job.getParent());
    +            return forGroup(job.getParent(), false);
             }
     
             @Override public Collection<LibraryConfiguration> fromConfiguration(StaplerRequest request) {
    -            return forGroup(request.findAncestorObject(AbstractFolder.class));
    +            return forGroup(request.findAncestorObject(AbstractFolder.class), true);
             }
     
             @Override public Collection<LibraryConfiguration> suggestedConfigurations(ItemGroup<?> group) {
    -            return forGroup(group);
    +            return forGroup(group, false);
             }
     
         }
    
  • src/main/java/org/jenkinsci/plugins/workflow/libs/GlobalLibraries.java+4 1 modified
    @@ -89,7 +89,10 @@ public void setLibraries(List<LibraryConfiguration> libraries) {
             }
     
             @Override public Collection<LibraryConfiguration> fromConfiguration(StaplerRequest request) {
    -            return GlobalLibraries.get().getLibraries();
    +            if (Jenkins.get().hasPermission(Jenkins.RUN_SCRIPTS)) {
    +                return GlobalLibraries.get().getLibraries();
    +            }
    +            return Collections.emptySet();
             }
     
             @Override public Collection<LibraryConfiguration> suggestedConfigurations(ItemGroup<?> group) {
    
  • src/main/java/org/jenkinsci/plugins/workflow/libs/LibraryConfiguration.java+2 0 modified
    @@ -45,6 +45,7 @@
     import org.kohsuke.stapler.QueryParameter;
     import org.kohsuke.stapler.Stapler;
     import org.kohsuke.stapler.StaplerRequest;
    +import org.kohsuke.stapler.interceptor.RequirePOST;
     
     /**
      * User configuration for one library.
    @@ -160,6 +161,7 @@ public FormValidation doCheckName(@QueryParameter String name) {
                 return FormValidation.ok();
             }
     
    +        @RequirePOST
             public FormValidation doCheckDefaultVersion(@AncestorInPath Item context, @QueryParameter String defaultVersion, @QueryParameter boolean implicit, @QueryParameter boolean allowVersionOverride, @QueryParameter String name) {
                 if (defaultVersion.isEmpty()) {
                     if (implicit) {
    
  • src/main/java/org/jenkinsci/plugins/workflow/libs/LibraryResolver.java+2 0 modified
    @@ -65,6 +65,8 @@ public abstract class LibraryResolver implements ExtensionPoint {
     
         /**
          * A list of libraries that may have already been configured in this context.
    +     * Implementations should only return libraries that the current user has
    +     * permission to configure in this context.
          * @param request a web request
          * @return known libraries, if any (empty by default)
          */
    
  • src/main/resources/org/jenkinsci/plugins/workflow/libs/LibraryConfiguration/config.jelly+1 1 modified
    @@ -29,7 +29,7 @@ THE SOFTWARE.
             <f:textbox/>
         </f:entry>
         <f:entry field="defaultVersion" title="${%Default version}">
    -        <f:textbox/>
    +        <f:textbox checkMethod="post"/>
         </f:entry>
         <f:entry field="implicit" title="${%Load implicitly}">
             <f:checkbox/>
    
  • src/test/java/org/jenkinsci/plugins/workflow/libs/FolderLibrariesTest.java+41 0 modified
    @@ -25,15 +25,21 @@
     package org.jenkinsci.plugins.workflow.libs;
     
     import com.cloudbees.hudson.plugins.folder.Folder;
    +import com.gargoylesoftware.htmlunit.HttpMethod;
    +import com.gargoylesoftware.htmlunit.WebRequest;
     import com.gargoylesoftware.htmlunit.html.HtmlForm;
     import com.gargoylesoftware.htmlunit.html.HtmlPage;
     import com.gargoylesoftware.htmlunit.html.HtmlTextArea;
    +import com.gargoylesoftware.htmlunit.util.NameValuePair;
     import com.google.common.collect.ImmutableMap;
    +import hudson.model.Item;
     import hudson.model.Result;
     import hudson.plugins.git.GitSCM;
    +import java.net.URL;
     import java.util.Arrays;
     import java.util.Collections;
     import java.util.List;
    +import jenkins.model.Jenkins;
     import jenkins.plugins.git.GitSCMSource;
     import jenkins.plugins.git.GitSampleRepoRule;
     import jenkins.scm.impl.subversion.SubversionSCMSource;
    @@ -53,6 +59,7 @@
     import org.jvnet.hudson.test.BuildWatcher;
     import org.jvnet.hudson.test.Issue;
     import org.jvnet.hudson.test.JenkinsRule;
    +import org.jvnet.hudson.test.MockAuthorizationStrategy;
     
     public class FolderLibrariesTest {
     
    @@ -214,6 +221,40 @@ public class FolderLibrariesTest {
             }
         }
     
    +    @Issue("SECURITY-1422")
    +    @Test public void checkDefaultVersionRestricted() throws Exception {
    +        sampleRepo1.init();
    +        sampleRepo1.write("vars/myecho.groovy", "def call() {echo 'something special'}");
    +        sampleRepo1.git("add", "vars");
    +        sampleRepo1.git("commit", "--message=init");
    +        r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
    +        MockAuthorizationStrategy s = new MockAuthorizationStrategy()
    +                .grant(Jenkins.READ).everywhere().toEveryone()
    +                .grant(Item.READ).everywhere().toEveryone()
    +                .grant(Item.CONFIGURE).everywhere().to("admin");
    +        r.jenkins.setAuthorizationStrategy(s);
    +        LibraryConfiguration foo = new LibraryConfiguration("foo", new SCMSourceRetriever(new GitSCMSource(sampleRepo1.toString())));
    +        Folder f = r.jenkins.createProject(Folder.class, "f");
    +        f.getProperties().add(new FolderLibraries(Arrays.asList(foo)));
    +        JenkinsRule.WebClient wc = r.createWebClient();
    +        wc.setThrowExceptionOnFailingStatusCode(false);
    +        WebRequest req = new WebRequest(new URL(wc.getContextPath() + f.getUrl() + "/descriptorByName/" +
    +                LibraryConfiguration.class.getName() + "/checkDefaultVersion"), HttpMethod.POST);
    +        req.setRequestParameters(Arrays.asList(
    +                new NameValuePair("name", "foo"),
    +                new NameValuePair("defaultVersion", "master"),
    +                new NameValuePair("value", "master"),
    +                new NameValuePair("implicit", "false"),
    +                new NameValuePair("allowVersionOverride", "true")));
    +        wc.addCrumb(req);
    +        wc.login("user", "user");
    +        assertThat(wc.getPage(req).getWebResponse().getContentAsString(),
    +                containsString("Cannot validate default version until after saving and reconfiguring"));
    +        wc.login("admin", "admin");
    +        assertThat(wc.getPage(req).getWebResponse().getContentAsString(),
    +                containsString("Currently maps to revision"));
    +    }
    +
         // TODO test replay of `load`ed scripts as well as libraries
     
         // TODO test override of global or top folder scope
    
  • src/test/java/org/jenkinsci/plugins/workflow/libs/GlobalLibrariesTest.java+39 0 modified
    @@ -24,25 +24,32 @@
     
     package org.jenkinsci.plugins.workflow.libs;
     
    +import com.gargoylesoftware.htmlunit.HttpMethod;
    +import com.gargoylesoftware.htmlunit.WebRequest;
     import com.gargoylesoftware.htmlunit.html.HtmlPage;
    +import com.gargoylesoftware.htmlunit.util.NameValuePair;
     import hudson.model.Item;
     import hudson.model.View;
    +import java.net.URL;
     import java.util.Arrays;
     import java.util.Collections;
     import java.util.List;
     import jenkins.model.Jenkins;
     import jenkins.plugins.git.GitSCMSource;
    +import jenkins.plugins.git.GitSampleRepoRule;
     import jenkins.scm.impl.subversion.SubversionSCMSource;
     import static org.hamcrest.Matchers.*;
     import org.junit.Test;
     import static org.junit.Assert.*;
     import org.junit.Rule;
    +import org.jvnet.hudson.test.Issue;
     import org.jvnet.hudson.test.JenkinsRule;
     import org.jvnet.hudson.test.MockAuthorizationStrategy;
     
     public class GlobalLibrariesTest {
     
         @Rule public JenkinsRule r = new JenkinsRule();
    +    @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule();
     
         @Test public void configRoundtrip() throws Exception {
             r.configRoundtrip();
    @@ -71,4 +78,36 @@ public class GlobalLibrariesTest {
             r.assertEqualDataBoundBeans(Arrays.asList(foo, bar), libs);
         }
     
    +    @Issue("SECURITY-1422")
    +    @Test public void checkDefaultVersionRestricted() throws Exception {
    +        sampleRepo.init();
    +        sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}");
    +        sampleRepo.git("add", "vars");
    +        sampleRepo.git("commit", "--message=init");
    +        r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
    +        MockAuthorizationStrategy s = new MockAuthorizationStrategy()
    +            .grant(Jenkins.READ).everywhere().toEveryone()
    +            .grant(Jenkins.RUN_SCRIPTS).everywhere().to("admin");
    +        r.jenkins.setAuthorizationStrategy(s);
    +        LibraryConfiguration foo = new LibraryConfiguration("foo", new SCMSourceRetriever(new GitSCMSource(sampleRepo.toString())));
    +        GlobalLibraries.get().setLibraries(Arrays.asList(foo));
    +        JenkinsRule.WebClient wc = r.createWebClient();
    +        wc.setThrowExceptionOnFailingStatusCode(false);
    +        WebRequest req = new WebRequest(new URL(wc.getContextPath() + "/descriptorByName/" +
    +                LibraryConfiguration.class.getName() + "/checkDefaultVersion"), HttpMethod.POST);
    +        req.setRequestParameters(Arrays.asList(
    +                new NameValuePair("name", "foo"),
    +                new NameValuePair("defaultVersion", "master"),
    +                new NameValuePair("value", "master"),
    +                new NameValuePair("implicit", "false"),
    +                new NameValuePair("allowVersionOverride", "true")));
    +        wc.addCrumb(req);
    +        wc.login("user", "user");
    +        assertThat(wc.getPage(req).getWebResponse().getContentAsString(),
    +                containsString("Cannot validate default version until after saving and reconfiguring"));
    +        wc.login("admin", "admin");
    +        assertThat(wc.getPage(req).getWebResponse().getContentAsString(),
    +                containsString("Currently maps to revision"));
    +    }
    +
     }
    

Vulnerability mechanics

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

References

8

News mentions

0

No linked articles in our index yet.