CVE-2020-2141
Description
A cross-site request forgery vulnerability in Jenkins P4 Plugin 1.10.10 and earlier allows attackers to trigger builds or add a labels in Perforce.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A CSRF vulnerability in Jenkins P4 Plugin (≤1.10.10) lets attackers trigger builds or add labels in Perforce.
Vulnerability
The Jenkins P4 Plugin (Perforce plugin) versions 1.10.10 and earlier contain a cross-site request forgery (CSRF) vulnerability (CVE-2020-2141). The plugin did not require a valid CSRF token or confirm that POST requests originated from the Jenkins UI for endpoints that trigger builds or add labels in Perforce [1][3]. This lack of protection allows an attacker to trick a Jenkins user into performing unintended actions.
Exploitation
To exploit this, an attacker must convince an authenticated Jenkins user (with sufficient permissions) to visit a malicious web page or click a crafted link while logged into Jenkins. No additional prerequisites are needed beyond network access to the victim's browser. The vulnerable endpoints are doBuildSubmit, doBuild, and the tagging doSubmit action, which were missing the @POST annotation required by Stapler for CSRF protection [3].
Impact
A successful CSRF attack can trigger arbitrary builds (even on projects the attacker cannot normally access) and add labels in Perforce, potentially disrupting operations, introducing malicious code into builds, or polluting Perforce metadata. This could lead to supply‑chain compromise or denial of service within the Jenkins‑Perforce pipeline [1][4].
Mitigation
Jenkins P4 Plugin version 1.10.11 was released to fix this vulnerability by properly annotating the vulnerable methods with @POST and adding permission checks [2][3]. Administrators should upgrade to 1.10.11 or later immediately. No workarounds are known if upgrading is not possible. This CVE is not listed in CISA's Known Exploited Vulnerabilities catalog as of this writing.
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:p4Maven | < 1.10.11 | 1.10.11 |
Affected products
3- Range: <=1.10.10
- Range: unspecified
Patches
14 files changed · +27 −7
src/main/java/org/jenkinsci/plugins/p4/review/ReviewAction.java+7 −2 modified@@ -1,9 +1,9 @@ package org.jenkinsci.plugins.p4.review; -import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.Cause; import hudson.model.CauseAction; +import hudson.model.Item; import hudson.model.Job; import hudson.model.ParameterDefinition; import hudson.model.ParameterValue; @@ -17,6 +17,7 @@ import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; import javax.servlet.ServletException; import java.io.IOException; @@ -67,17 +68,21 @@ public List<StringParameterValue> getAvailableParameters() { return stringParameters; } + @POST public void doBuildSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { + project.checkPermission(Item.BUILD); + JSONObject formData = req.getSubmittedForm(); if (!formData.isEmpty()) { doBuild(req, rsp); } } + @POST public void doBuild(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - project.checkPermission(AbstractProject.BUILD); + project.checkPermission(Item.BUILD); List<ParameterValue> values = new ArrayList<ParameterValue>(); List<ParameterDefinition> defs = new ArrayList<ParameterDefinition>();
src/main/java/org/jenkinsci/plugins/p4/tagging/TagAction.java+3 −1 modified@@ -23,6 +23,7 @@ import org.jenkinsci.plugins.p4.workspace.Workspace; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; import javax.servlet.ServletException; import java.io.File; @@ -84,6 +85,7 @@ public boolean isTagged() { return tags != null && !tags.isEmpty(); } + @POST public void doSubmit(StaplerRequest req, StaplerResponse rsp) throws Exception, ServletException { getACL().checkPermission(PerforceScm.TAG); @@ -274,7 +276,7 @@ public static List<P4Ref> getLastChange(Run<?, ?> run, TaskListener listener, St // Fetch all syncIDs and check for duplicates JENKINS-55075 List<String> syncList = new ArrayList<>(); for (TagAction action : actions) { - if(syncList.contains(action.getSyncID())) { + if (syncList.contains(action.getSyncID())) { listener.getLogger().println("WARNING: duplicate syncID found: " + action.getSyncID()); logger.severe("WARNING: duplicate syncID found: " + action.getSyncID()); }
src/main/java/org/jenkinsci/plugins/p4/trigger/P4Hook.java+16 −3 modified@@ -2,6 +2,7 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import hudson.Extension; +import hudson.model.Item; import hudson.model.Job; import hudson.model.UnprotectedRootAction; import jenkins.model.Jenkins; @@ -14,6 +15,7 @@ import org.jenkinsci.plugins.p4.scm.events.P4BranchSCMHeadEvent; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; import javax.servlet.ServletException; import java.io.IOException; @@ -24,6 +26,8 @@ import java.util.concurrent.Executors; import java.util.logging.Logger; +import static hudson.Functions.checkPermission; + @Extension public class P4Hook implements UnprotectedRootAction { @@ -46,8 +50,11 @@ public String getUrlName() { return URLNAME; } + @POST public void doEvent(StaplerRequest req) throws ServletException, IOException { + checkPermission(Item.BUILD); + // exit early if no json String contentType = req.getContentType(); if (contentType == null || !contentType.startsWith("application/json")) { @@ -66,7 +73,11 @@ public void doEvent(StaplerRequest req) throws ServletException, IOException { SCMHeadEvent.fireNow(new P4BranchSCMHeadEvent(eventType, payload, SCMEvent.originOf(req))); } - public void doChange(StaplerRequest req) throws IOException { + @POST + public void doChange(StaplerRequest req) throws ServletException, IOException { + + checkPermission(Item.BUILD); + String body = IOUtils.toString(req.getInputStream(), Charset.forName("UTF-8")); String contentType = req.getContentType(); if (contentType != null && contentType.startsWith("application/json")) { @@ -102,8 +113,10 @@ public void run() { } } - public void doChangeSubmit(StaplerRequest req, StaplerResponse rsp) - throws IOException, ServletException { + @POST + public void doChangeSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { + + checkPermission(Item.BUILD); JSONObject formData = req.getSubmittedForm(); if (!formData.isEmpty()) {
src/main/resources/org/jenkinsci/plugins/p4/tagging/TagAction/tagForm.jelly+1 −1 modified@@ -40,7 +40,7 @@ <p><b>Create a Perforce Automatic label:</b></p> <p>The Label's view is based on the workspace used during the build and Revision is set to change number: ${it.buildChange}.</p> - <form action="submit" method="get" name="label"> + <form action="submit" method="post" name="label"> <table border="0" width="640"> <tr> <td nowrap="nowrap"><b>Label Name:</b> </td>
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-rjjq-63c7-8724ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-2141ghsaADVISORY
- www.openwall.com/lists/oss-security/2020/03/09/1ghsamailing-listx_refsource_MLISTWEB
- github.com/jenkinsci/p4-plugin/commit/2f2a31d8d36de7abab45820fab3a82f4c682b760ghsaWEB
- jenkins.io/security/advisory/2020-03-09/ghsax_refsource_CONFIRMWEB
News mentions
1- Jenkins Security Advisory 2020-03-09Jenkins Security Advisories · Mar 9, 2020