CVE-2021-21633
Description
CSRF in Jenkins OWASP Dependency-Track Plugin ≤3.1.0 lets attackers connect to attacker-controlled URLs, capturing stored Jenkins credentials.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CSRF in Jenkins OWASP Dependency-Track Plugin ≤3.1.0 lets attackers connect to attacker-controlled URLs, capturing stored Jenkins credentials.
Vulnerability
Overview CVE-2021-21633 is a cross-site request forgery (CSRF) vulnerability in the Jenkins OWASP Dependency-Track Plugin version 3.1.0 and earlier [1][3]. The plugin fails to require a CSRF token for certain HTTP endpoints, allowing an attacker to trick an authenticated Jenkins user into making a request that causes the plugin to connect to an attacker-specified URL [1]. This action can capture credentials stored in Jenkins, such as API keys or other secrets.
Exploitation
An attacker can exploit this vulnerability by crafting a malicious link or form and luring a Jenkins user with sufficient permissions (e.g., Job/Configure or overall Configure access) to click it [1]. The plugin then sends a request to the attacker-controlled URL, transmitting stored credentials in the process [3]. No direct network access to Jenkins is required; the attack relies on social engineering.
Impact
Successful exploitation allows the attacker to obtain credentials stored in Jenkins, which could be used to access other systems or escalate privileges within Jenkins [1][3]. The severity is rated as medium (CVSS 6.5) according to the Jenkins security advisory [1].
Mitigation
The vulnerability is fixed in OWASP Dependency-Track Plugin version 3.1.1 [4]. Users should upgrade immediately. No workaround is available [1].
AI Insight generated on May 21, 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:dependency-trackMaven | < 3.1.1 | 3.1.1 |
Affected products
2- Range: 1.1.0
Patches
170e7b82ad9a1[SECURITY-2250]
5 files changed · +37 −11
CHANGELOG.md+3 −0 modified@@ -1,6 +1,9 @@ # Dependency-Track Jenkins Plugin - Changelog ## Unreleased +## v3.1.1 - 2021-03-30 +### 🐞 Bugs Fixed +- [SECURITY-2250](https://issues.jenkins.io/browse/SECURITY-2250). Thanks to Justin Philip for reporting this issue. ## v3.1.0 - 2021-02-08 ### ⭐ New Features
src/main/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImpl.java+26 −3 modified@@ -46,6 +46,7 @@ import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.verb.POST; /** * <p> @@ -149,6 +150,7 @@ public boolean isApplicable(Class<? extends AbstractProject> aClass) { * @param item used to lookup credentials in job config. ignored in global * @return ListBoxModel */ + @POST public ListBoxModel doFillProjectIdItems(@QueryParameter final String dependencyTrackUrl, @QueryParameter final String dependencyTrackApiKey, @AncestorInPath @Nullable Item item) { final ListBoxModel projects = new ListBoxModel(); try { @@ -169,6 +171,7 @@ public ListBoxModel doFillProjectIdItems(@QueryParameter final String dependency return projects; } + @POST public ListBoxModel doFillDependencyTrackApiKeyItems(@QueryParameter String credentialsId, @AncestorInPath Item item) { StandardListBoxModel result = new StandardListBoxModel(); if (item == null) { @@ -190,19 +193,33 @@ public ListBoxModel doFillDependencyTrackApiKeyItems(@QueryParameter String cred * Performs input validation when submitting the global config * * @param value The value of the URL as specified in the global config + * @param item used to check permissions in job config. ignored in global * @return a FormValidation object */ - public FormValidation doCheckDependencyTrackUrl(@QueryParameter String value) { + @POST + public FormValidation doCheckDependencyTrackUrl(@QueryParameter String value, @AncestorInPath @Nullable Item item) { + if (item == null) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + } else { + item.checkPermission(Item.CONFIGURE); + } return PluginUtil.doCheckUrl(value); } /** * Performs input validation when submitting the global config * * @param value The value of the URL as specified in the global config + * @param item used to check permissions in job config. ignored in global * @return a FormValidation object */ - public FormValidation doCheckDependencyTrackFrontendUrl(@QueryParameter String value) { + @POST + public FormValidation doCheckDependencyTrackFrontendUrl(@QueryParameter String value, @AncestorInPath @Nullable Item item) { + if (item == null) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + } else { + item.checkPermission(Item.CONFIGURE); + } return PluginUtil.doCheckUrl(value); } @@ -217,12 +234,18 @@ public FormValidation doCheckDependencyTrackFrontendUrl(@QueryParameter String v * config * @return FormValidation */ + @POST public FormValidation doTestConnection(@QueryParameter final String dependencyTrackUrl, @QueryParameter final String dependencyTrackApiKey, @AncestorInPath @Nullable Item item) { + if (item == null) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + } else { + item.checkPermission(Item.CONFIGURE); + } // url may come from instance-config. if empty, then take it from global config (this) final String url = Optional.ofNullable(PluginUtil.parseBaseUrl(dependencyTrackUrl)).orElse(getDependencyTrackUrl()); // api-key may come from instance-config. if empty, then take it from global config (this) final String apiKey = lookupApiKey(Optional.ofNullable(StringUtils.trimToNull(dependencyTrackApiKey)).orElse(getDependencyTrackApiKey()), item); - if (doCheckDependencyTrackUrl(url).kind == FormValidation.Kind.OK && StringUtils.isNotBlank(apiKey)) { + if (doCheckDependencyTrackUrl(url, item).kind == FormValidation.Kind.OK && StringUtils.isNotBlank(apiKey)) { try { final ApiClient apiClient = getClient(url, apiKey); final String result = apiClient.testConnection();
src/main/resources/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher/config.jelly+2 −2 modified@@ -39,10 +39,10 @@ limitations under the License. <f:optionalBlock inline="true" field="overrideGlobals" title="${%overrideGlobals}"> <f:entry title="${%dependencytrack.url}" field="dependencyTrackUrl" help="/plugin/dependency-track/help-dt-url.html"> - <f:textbox id="dependencytrack.url" /> + <f:textbox id="dependencytrack.url" checkMethod="post" /> </f:entry> <f:entry title="${%dependencytrack.url.frontend}" field="dependencyTrackFrontendUrl" help="/plugin/dependency-track/help-dt-url-frontend.html"> - <f:textbox id="dependencytrack.url.frontend"/> + <f:textbox id="dependencytrack.url.frontend" checkMethod="post" /> </f:entry> <f:entry title="${%dependencytrack.apikey}" field="dependencyTrackApiKey" help="/plugin/dependency-track/help-dt-apikey.html"> <c:select id="dependencytrack.apikey" />
src/main/resources/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher/global.jelly+2 −2 modified@@ -18,7 +18,7 @@ limitations under the License. <f:section title="Dependency-Track"> <f:entry title="${%dependencytrack.url}" field="dependencyTrackUrl" help="/plugin/dependency-track/help-dt-url.html"> - <f:textbox id="dependencytrack.url"/> + <f:textbox id="dependencytrack.url" checkMethod="post" /> </f:entry> <f:entry title="${%dependencytrack.apikey}" field="dependencyTrackApiKey" help="/plugin/dependency-track/help-dt-apikey.html"> <c:select id="dependencytrack.apikey" /> @@ -28,7 +28,7 @@ limitations under the License. </f:entry> <f:advanced> <f:entry title="${%dependencytrack.url.frontend}" field="dependencyTrackFrontendUrl" help="/plugin/dependency-track/help-dt-url-frontend.html"> - <f:textbox id="dependencytrack.url.frontend"/> + <f:textbox id="dependencytrack.url.frontend" checkMethod="post" /> </f:entry> <f:entry title="${%dependencytrack.polling.timeout}" field="dependencyTrackPollingTimeout" help="/plugin/dependency-track/help-dt-polling-timeout.html"> <f:number id="dependencytrack.polling.timeout" default="5" clazz="positive-number" />
src/test/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImplTest.java+4 −4 modified@@ -162,10 +162,10 @@ public void doTestConnectionTestWithEmptyArgs() throws ApiClientException, IOExc @Test public void doCheckDependencyTrackUrlTest() { - assertThat(uut.doCheckDependencyTrackUrl("http://foo.bar/")).isEqualTo(FormValidation.ok()); - assertThat(uut.doCheckDependencyTrackUrl("http://foo.bar")).isEqualTo(FormValidation.ok()); - assertThat(uut.doCheckDependencyTrackUrl("")).isEqualTo(FormValidation.ok()); - assertThat(uut.doCheckDependencyTrackUrl("foo")) + assertThat(uut.doCheckDependencyTrackUrl("http://foo.bar/", null)).isEqualTo(FormValidation.ok()); + assertThat(uut.doCheckDependencyTrackUrl("http://foo.bar", null)).isEqualTo(FormValidation.ok()); + assertThat(uut.doCheckDependencyTrackUrl("", null)).isEqualTo(FormValidation.ok()); + assertThat(uut.doCheckDependencyTrackUrl("foo", null)) .hasFieldOrPropertyWithValue("kind", FormValidation.Kind.ERROR) .hasMessage("The specified value is not a valid URL"); }
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-v7xh-h48c-xw5fghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-21633ghsaADVISORY
- www.openwall.com/lists/oss-security/2021/03/30/1ghsamailing-listx_refsource_MLISTWEB
- github.com/jenkinsci/dependency-track-plugin/commit/70e7b82ad9a10499e628998a0bcb57c1481c66bcghsaWEB
- www.jenkins.io/security/advisory/2021-03-30/ghsax_refsource_CONFIRMWEB
News mentions
1- Jenkins Security Advisory 2021-03-30Jenkins Security Advisories · Mar 30, 2021