VYPR
Moderate severityNVD Advisory· Published Oct 16, 2019· Updated Aug 4, 2024

CVE-2019-10438

CVE-2019-10438

Description

Missing permission check in Jenkins CRX Content Package Deployer Plugin allows attackers with Overall/Read to capture stored credentials via attacker-controlled URL and credential IDs.

AI Insight

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

Missing permission check in Jenkins CRX Content Package Deployer Plugin allows attackers with Overall/Read to capture stored credentials via attacker-controlled URL and credential IDs.

Vulnerability

Overview

CVE-2019-10438 is a missing permission check in the Jenkins CRX Content Package Deployer Plugin versions 1.8.1 and earlier. The plugin's form validation method did not verify that the user had the necessary permissions, allowing any user with Overall/Read access to trigger a connection to an attacker-specified URL using attacker-specified credential IDs [1][2].

Exploitation

An attacker must have Overall/Read permission on the Jenkins instance and obtain valid credential IDs through another method (e.g., a separate vulnerability). The form validation method also lacked a POST requirement, making it vulnerable to CSRF attacks [1]. This combination enables the attacker to craft a request that causes the plugin to connect to an attacker-controlled server using the specified credentials.

Impact

Successful exploitation allows the attacker to capture credentials stored in Jenkins by having the plugin authenticate to an attacker-controlled server with those credentials. This can lead to credential theft and further compromise of the Jenkins environment [1][2].

Mitigation

The vulnerability is fixed in CRX Content Package Deployer Plugin version 1.9. The fix adds proper permission checks and enforces POST requests on the affected method [1][3]. Users should upgrade to version 1.9 or later immediately.

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:crx-content-package-deployerMaven
< 1.91.9

Affected products

2

Patches

1
1313c422170a

add @RequirePOST annotation and checkPermission configure

12 files changed · +100 72
  • src/main/java/org/jenkinsci/plugins/graniteclient/BuildPackageBuilder.java+12 7 modified
    @@ -27,10 +27,6 @@
     
     package org.jenkinsci.plugins.graniteclient;
     
    -import java.io.IOException;
    -import javax.annotation.Nonnull;
    -import javax.servlet.ServletException;
    -
     import com.cloudbees.plugins.credentials.common.AbstractIdCredentialsListBoxModel;
     import hudson.Extension;
     import hudson.FilePath;
    @@ -53,6 +49,11 @@
     import org.kohsuke.stapler.DataBoundConstructor;
     import org.kohsuke.stapler.DataBoundSetter;
     import org.kohsuke.stapler.QueryParameter;
    +import org.kohsuke.stapler.interceptor.RequirePOST;
    +
    +import javax.annotation.Nonnull;
    +import javax.servlet.ServletException;
    +import java.io.IOException;
     
     /**
      * Implementation of the "Build a Content Package on CRX" build step
    @@ -89,7 +90,7 @@ public BuildPackageBuilder(String packageId, String baseUrl, String credentialsI
         }
     
         public void perform(@Nonnull Run<?, ?> build, @Nonnull FilePath workspace, @Nonnull Launcher launcher,
    -                    @Nonnull TaskListener listener) throws InterruptedException, IOException {
    +                        @Nonnull TaskListener listener) throws InterruptedException, IOException {
     
             Result result = Result.SUCCESS;
             Result buildResult = build.getResult();
    @@ -269,18 +270,22 @@ public boolean isApplicable(Class<? extends AbstractProject> aClass) {
                 return true;
             }
     
    +        @RequirePOST
             public AbstractIdCredentialsListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context,
                                                                               @QueryParameter("baseUrl") String baseUrl,
                                                                               @QueryParameter("value") String value) {
    +            context.checkPermission(Item.CONFIGURE);
                 return GraniteCredentialsListBoxModel.fillItems(value, context, baseUrl);
             }
     
    -        public FormValidation doTestConnection(@QueryParameter("baseUrl") final String baseUrl,
    +        @RequirePOST
    +        public FormValidation doTestConnection(@AncestorInPath Item context,
    +                                               @QueryParameter("baseUrl") final String baseUrl,
                                                    @QueryParameter("credentialsId") final String credentialsId,
                                                    @QueryParameter("requestTimeout") final long requestTimeout,
                                                    @QueryParameter("serviceTimeout") final long serviceTimeout)
                     throws IOException, ServletException {
    -
    +            context.checkPermission(Item.CONFIGURE);
                 return BaseUrlUtil.testOneConnection(baseUrl, credentialsId, requestTimeout, serviceTimeout);
             }
     
    
  • src/main/java/org/jenkinsci/plugins/graniteclient/DeployPackagesBuilder.java+35 30 modified
    @@ -27,23 +27,6 @@
     
     package org.jenkinsci.plugins.graniteclient;
     
    -import static org.jenkinsci.plugins.graniteclient.BaseUrlUtil.splitByNewline;
    -
    -import java.io.File;
    -import java.io.IOException;
    -import java.util.ArrayList;
    -import java.util.Arrays;
    -import java.util.Collections;
    -import java.util.Comparator;
    -import java.util.HashMap;
    -import java.util.HashSet;
    -import java.util.LinkedHashMap;
    -import java.util.List;
    -import java.util.Map;
    -import java.util.Set;
    -import javax.annotation.Nonnull;
    -import javax.servlet.ServletException;
    -
     import com.cloudbees.plugins.credentials.common.AbstractIdCredentialsListBoxModel;
     import hudson.Extension;
     import hudson.FilePath;
    @@ -70,6 +53,24 @@
     import org.kohsuke.stapler.DataBoundSetter;
     import org.kohsuke.stapler.QueryParameter;
     import org.kohsuke.stapler.StaplerRequest;
    +import org.kohsuke.stapler.interceptor.RequirePOST;
    +
    +import javax.annotation.Nonnull;
    +import javax.servlet.ServletException;
    +import java.io.File;
    +import java.io.IOException;
    +import java.util.ArrayList;
    +import java.util.Arrays;
    +import java.util.Collections;
    +import java.util.Comparator;
    +import java.util.HashMap;
    +import java.util.HashSet;
    +import java.util.LinkedHashMap;
    +import java.util.List;
    +import java.util.Map;
    +import java.util.Set;
    +
    +import static org.jenkinsci.plugins.graniteclient.BaseUrlUtil.splitByNewline;
     
     /**
      * Implementation of the "Deploy Content Packages to CRX" build step
    @@ -354,17 +355,17 @@ private Map<PackId, FilePath> selectPackages(@Nonnull final Run<?, ?> build,
     
                 Collections.sort(
                         listed, Collections.reverseOrder(
    -                    new Comparator<FilePath>() {
    -                        public int compare(FilePath left, FilePath right) {
    -                            try {
    -                                return Long.compare(left.lastModified(), right.lastModified());
    -                            } catch (Exception e) {
    -                                listener.error("Failed to compare a couple files: %s", e.getMessage());
    +                            new Comparator<FilePath>() {
    +                                public int compare(FilePath left, FilePath right) {
    +                                    try {
    +                                        return Long.compare(left.lastModified(), right.lastModified());
    +                                    } catch (Exception e) {
    +                                        listener.error("Failed to compare a couple files: %s", e.getMessage());
    +                                    }
    +                                    return 0;
    +                                }
                                 }
    -                            return 0;
    -                        }
    -                    }
    -            ));
    +                    ));
     
                 for (FilePath path : listed) {
                     PackId packId = path.act(new IdentifyPackageCallable());
    @@ -485,9 +486,11 @@ public boolean configure(StaplerRequest req, JSONObject json) throws FormExcepti
                 return true;
             }
     
    +        @RequirePOST
             public AbstractIdCredentialsListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context,
                                                                               @QueryParameter("baseUrls") String baseUrls,
                                                                               @QueryParameter("value") String value) {
    +            context.checkPermission(Item.CONFIGURE);
                 List<String> _baseUrls = splitByNewline(baseUrls);
     
                 if (!_baseUrls.isEmpty()) {
    @@ -497,12 +500,14 @@ public AbstractIdCredentialsListBoxModel doFillCredentialsIdItems(@AncestorInPat
                 }
             }
     
    -        public FormValidation doTestConnection(@QueryParameter("baseUrls") final String baseUrls,
    +        @RequirePOST
    +        public FormValidation doTestConnection(@AncestorInPath Item context,
    +                                               @QueryParameter("baseUrls") final String baseUrls,
                                                    @QueryParameter("credentialsId") final String credentialsId,
                                                    @QueryParameter("requestTimeout") final long requestTimeout,
                                                    @QueryParameter("serviceTimeout") final long serviceTimeout)
                     throws IOException, ServletException {
    -
    +            context.checkPermission(Item.CONFIGURE);
                 return BaseUrlUtil.testManyConnections(baseUrls, credentialsId, requestTimeout, serviceTimeout);
             }
     
    @@ -515,7 +520,7 @@ public ListBoxModel doFillAcHandlingItems() {
                         ACHandling.MERGE,
                         ACHandling.OVERWRITE,
                         ACHandling.CLEAR)
    -                    ) {
    +            ) {
                     model.add(mode.getLabel(), mode.name());
                 }
                 return model;
    
  • src/main/java/org/jenkinsci/plugins/graniteclient/DownloadPackagesBuilder.java+14 9 modified
    @@ -27,13 +27,6 @@
     
     package org.jenkinsci.plugins.graniteclient;
     
    -import java.io.IOException;
    -import java.util.ArrayList;
    -import java.util.Collections;
    -import java.util.List;
    -import javax.annotation.Nonnull;
    -import javax.servlet.ServletException;
    -
     import com.cloudbees.plugins.credentials.common.AbstractIdCredentialsListBoxModel;
     import hudson.Extension;
     import hudson.FilePath;
    @@ -55,6 +48,14 @@
     import org.kohsuke.stapler.DataBoundConstructor;
     import org.kohsuke.stapler.DataBoundSetter;
     import org.kohsuke.stapler.QueryParameter;
    +import org.kohsuke.stapler.interceptor.RequirePOST;
    +
    +import javax.annotation.Nonnull;
    +import javax.servlet.ServletException;
    +import java.io.IOException;
    +import java.util.ArrayList;
    +import java.util.Collections;
    +import java.util.List;
     
     /**
      * Implementation of the "Download Content Packages from CRX" build step
    @@ -268,18 +269,22 @@ public boolean isApplicable(Class<? extends AbstractProject> aClass) {
                 return true;
             }
     
    +        @RequirePOST
             public AbstractIdCredentialsListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context,
                                                                               @QueryParameter("baseUrl") String baseUrl,
                                                                               @QueryParameter("value") String value) {
    +            context.checkPermission(Item.CONFIGURE);
                 return GraniteCredentialsListBoxModel.fillItems(value, context, baseUrl);
             }
     
    -        public FormValidation doTestConnection(@QueryParameter("baseUrl") final String baseUrl,
    +        @RequirePOST
    +        public FormValidation doTestConnection(@AncestorInPath Item context,
    +                                               @QueryParameter("baseUrl") final String baseUrl,
                                                    @QueryParameter("credentialsId") final String credentialsId,
                                                    @QueryParameter("requestTimeout") final long requestTimeout,
                                                    @QueryParameter("serviceTimeout") final long serviceTimeout)
                     throws IOException, ServletException {
    -
    +            context.checkPermission(Item.CONFIGURE);
                 return BaseUrlUtil.testOneConnection(baseUrl, credentialsId, requestTimeout, serviceTimeout);
             }
     
    
  • src/main/java/org/jenkinsci/plugins/graniteclient/GraniteAHCFactory.java+3 0 modified
    @@ -55,6 +55,7 @@
     import org.kohsuke.stapler.AncestorInPath;
     import org.kohsuke.stapler.QueryParameter;
     import org.kohsuke.stapler.StaplerRequest;
    +import org.kohsuke.stapler.interceptor.RequirePOST;
     
     /**
      * Global extension and configurable factory for {@link AsyncHttpClient} instances
    @@ -144,8 +145,10 @@ public String getDisplayName() {
             return "CRX Content Package Deployer - HTTP Client";
         }
     
    +    @RequirePOST
         public AbstractIdCredentialsListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context,
                                                                           @QueryParameter("value") String value) {
    +        context.checkPermission(Item.CONFIGURE);
             return GraniteCredentialsListBoxModel.fillItems(value, context);
         }
     
    
  • src/main/java/org/jenkinsci/plugins/graniteclient/PackageChoiceParameterDefinition.java+14 9 modified
    @@ -27,13 +27,6 @@
     
     package org.jenkinsci.plugins.graniteclient;
     
    -import java.io.IOException;
    -import java.util.ArrayList;
    -import java.util.Collections;
    -import java.util.Iterator;
    -import java.util.List;
    -import javax.servlet.ServletException;
    -
     import com.cloudbees.plugins.credentials.common.AbstractIdCredentialsListBoxModel;
     import hudson.Extension;
     import hudson.model.Item;
    @@ -52,6 +45,14 @@
     import org.kohsuke.stapler.DataBoundConstructor;
     import org.kohsuke.stapler.QueryParameter;
     import org.kohsuke.stapler.StaplerRequest;
    +import org.kohsuke.stapler.interceptor.RequirePOST;
    +
    +import javax.servlet.ServletException;
    +import java.io.IOException;
    +import java.util.ArrayList;
    +import java.util.Collections;
    +import java.util.Iterator;
    +import java.util.List;
     
     /**
      * Implementation of the "CRX Content Package Choice Parameter" type
    @@ -68,18 +69,22 @@ public String getDisplayName() {
                 return "CRX Content Package Choice Parameter";
             }
     
    -        public FormValidation doTestConnection(@QueryParameter("baseUrl") final String baseUrl,
    +        @RequirePOST
    +        public FormValidation doTestConnection(@AncestorInPath Item context,
    +                                               @QueryParameter("baseUrl") final String baseUrl,
                                                    @QueryParameter("credentialsId") final String credentialsId,
                                                    @QueryParameter("requestTimeout") final long requestTimeout,
                                                    @QueryParameter("serviceTimeout") final long serviceTimeout)
                     throws IOException, ServletException {
    -
    +            context.checkPermission(Item.CONFIGURE);
                 return BaseUrlUtil.testOneConnection(baseUrl, credentialsId, requestTimeout, serviceTimeout);
             }
     
    +        @RequirePOST
             public AbstractIdCredentialsListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context,
                                                                               @QueryParameter("baseUrl") String baseUrl,
                                                                               @QueryParameter("value") String value) {
    +            context.checkPermission(Item.CONFIGURE);
                 return GraniteCredentialsListBoxModel.fillItems(value, context, baseUrl);
             }
     
    
  • src/main/java/org/jenkinsci/plugins/graniteclient/ReplicatePackagesBuilder.java+16 11 modified
    @@ -27,15 +27,6 @@
     
     package org.jenkinsci.plugins.graniteclient;
     
    -import static org.jenkinsci.plugins.graniteclient.BaseUrlUtil.splitByNewline;
    -
    -import java.io.IOException;
    -import java.util.ArrayList;
    -import java.util.Collections;
    -import java.util.List;
    -import javax.annotation.Nonnull;
    -import javax.servlet.ServletException;
    -
     import com.cloudbees.plugins.credentials.common.AbstractIdCredentialsListBoxModel;
     import hudson.Extension;
     import hudson.FilePath;
    @@ -57,6 +48,16 @@
     import org.kohsuke.stapler.DataBoundConstructor;
     import org.kohsuke.stapler.DataBoundSetter;
     import org.kohsuke.stapler.QueryParameter;
    +import org.kohsuke.stapler.interceptor.RequirePOST;
    +
    +import javax.annotation.Nonnull;
    +import javax.servlet.ServletException;
    +import java.io.IOException;
    +import java.util.ArrayList;
    +import java.util.Collections;
    +import java.util.List;
    +
    +import static org.jenkinsci.plugins.graniteclient.BaseUrlUtil.splitByNewline;
     
     /**
      * Implementation of the "Replicate Content Packages from CRX" build step
    @@ -240,9 +241,11 @@ public boolean isApplicable(Class<? extends AbstractProject> aClass) {
                 return true;
             }
     
    +        @RequirePOST
             public AbstractIdCredentialsListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context,
                                                                               @QueryParameter("baseUrls") String baseUrls,
                                                                               @QueryParameter("value") String value) {
    +            context.checkPermission(Item.CONFIGURE);
                 List<String> _baseUrls = splitByNewline(baseUrls);
     
                 if (!_baseUrls.isEmpty()) {
    @@ -252,12 +255,14 @@ public AbstractIdCredentialsListBoxModel doFillCredentialsIdItems(@AncestorInPat
                 }
             }
     
    -        public FormValidation doTestConnection(@QueryParameter("baseUrls") final String baseUrls,
    +        @RequirePOST
    +        public FormValidation doTestConnection(@AncestorInPath Item context,
    +                                               @QueryParameter("baseUrls") final String baseUrls,
                                                    @QueryParameter("credentialsId") final String credentialsId,
                                                    @QueryParameter("requestTimeout") final long requestTimeout,
                                                    @QueryParameter("serviceTimeout") final long serviceTimeout)
                     throws IOException, ServletException {
    -
    +            context.checkPermission(Item.CONFIGURE);
                 return BaseUrlUtil.testManyConnections(baseUrls, credentialsId, requestTimeout, serviceTimeout);
             }
     
    
  • src/main/resources/org/jenkinsci/plugins/graniteclient/BuildPackageBuilder/config.jelly+1 1 modified
    @@ -54,7 +54,7 @@
     
         <f:advanced title="Connection Options">
             <f:entry title="Credentials" field="credentialsId">
    -            <creds:select />
    +            <creds:select checkMethod="post"/>
             </f:entry>
     
             <f:validateButton
    
  • src/main/resources/org/jenkinsci/plugins/graniteclient/DeployPackagesBuilder/config.jelly+1 1 modified
    @@ -69,7 +69,7 @@
         <f:advanced title="Connection Options">
     
             <f:entry title="Credentials" field="credentialsId">
    -            <creds:select />
    +            <creds:select checkMethod="post"/>
             </f:entry>
     
             <f:validateButton
    
  • src/main/resources/org/jenkinsci/plugins/graniteclient/DownloadPackagesBuilder/config.jelly+1 1 modified
    @@ -51,7 +51,7 @@
         <f:advanced title="Connection Options">
     
             <f:entry title="Credentials" field="credentialsId">
    -            <creds:select />
    +            <creds:select checkMethod="post"/>
             </f:entry>
     
             <f:validateButton
    
  • src/main/resources/org/jenkinsci/plugins/graniteclient/GraniteAHCFactory/global.jelly+1 1 modified
    @@ -30,7 +30,7 @@
         <f:section title="CRX Content Package Deployer - HTTP Client" name="GraniteAHCFactory">
     
             <f:entry title="Default Credentials" field="credentialsId">
    -            <creds:select />
    +            <creds:select checkMethod="post"/>
             </f:entry>
     
             <f:entry title="Preempt Login Base URL Patterns" field="preemptLoginForBaseUrls">
    
  • src/main/resources/org/jenkinsci/plugins/graniteclient/PackageChoiceParameterDefinition/config.jelly+1 1 modified
    @@ -68,7 +68,7 @@
         <f:advanced title="Connection Options">
     
             <f:entry title="Credentials" field="credentialsId">
    -            <creds:select />
    +            <creds:select checkMethod="post"/>
             </f:entry>
     
             <f:validateButton
    
  • src/main/resources/org/jenkinsci/plugins/graniteclient/ReplicatePackagesBuilder/config.jelly+1 1 modified
    @@ -43,7 +43,7 @@
         <f:advanced title="Connection Options">
     
             <f:entry title="Credentials" field="credentialsId">
    -            <creds:select />
    +            <creds:select checkMethod="post"/>
             </f:entry>
     
             <f:validateButton
    

Vulnerability mechanics

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

References

5

News mentions

0

No linked articles in our index yet.