CVE-2019-10437
Description
CSRF in Jenkins CRX Content Package Deployer Plugin allowed attackers to capture stored credentials by tricking users into submitting malicious requests.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CSRF in Jenkins CRX Content Package Deployer Plugin allowed attackers to capture stored credentials by tricking users into submitting malicious requests.
Vulnerability
Description
A cross-site request forgery (CSRF) vulnerability exists in Jenkins CRX Content Package Deployer Plugin versions 1.8.1 and earlier. The plugin's form validation method did not require POST requests and lacked proper permission checks, allowing attackers to perform unauthorized actions on behalf of authenticated users [1][2].
Exploitation
Attackers can craft a malicious link or form that, when clicked by an authenticated Jenkins user with Overall/Read access, triggers a request to connect to an attacker-specified URL using attacker-specified credentials IDs. The credentials IDs can be obtained through another method (e.g., by exploiting a separate vulnerability) [1][2].
Impact
Successful exploitation enables the attacker to capture credentials stored in Jenkins, such as API tokens, passwords, or other secrets. This can lead to further compromise of Jenkins and connected systems, potentially allowing unauthorized access to sensitive resources [1][2].
Mitigation
The issue is fixed in CRX Content Package Deployer Plugin version 1.9.0. The fix adds the @RequirePOST annotation to the form validation method and implements proper permission checks to prevent CSRF and unauthorized access [3]. Users are strongly advised to upgrade to the latest version 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.
| Package | Affected versions | Patched versions |
|---|---|---|
org.jenkins-ci.plugins:crx-content-package-deployerMaven | < 1.9 | 1.9 |
Affected products
2- Range: 1.8.1 and earlier
Patches
11313c422170aadd @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- github.com/advisories/GHSA-62fp-j75q-mqhcghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2019-10437ghsaADVISORY
- github.com/jenkinsci/crx-content-package-deployer-plugin/commit/1313c422170a064dab0f9359324ff27e30a9f4a5ghsaWEB
- jenkins.io/security/advisory/2019-10-16/mitrex_refsource_CONFIRM
- jenkins.io/security/advisory/2019-10-16/ghsaWEB
News mentions
0No linked articles in our index yet.