CVE-2023-43502
Description
A cross-site request forgery (CSRF) vulnerability in Jenkins Build Failure Analyzer Plugin 2.4.1 and earlier allows attackers to delete Failure Causes.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CSRF in Jenkins Build Failure Analyzer Plugin 2.4.1 and earlier lets attackers delete configured Failure Causes without user consent.
Vulnerability
Overview
A cross-site request forgery (CSRF) vulnerability exists in the Jenkins Build Failure Analyzer Plugin version 2.4.1 and earlier. The plugin fails to require a POST request for the endpoint that handles deletion of Failure Causes, making it susceptible to CSRF attacks [1][2].
Exploitation
An attacker can craft a malicious web page, link, or email that, when visited by an authenticated Jenkins user (who has at least the basic level of access to use the plugin), triggers an unauthorized request to delete Failure Causes. Because the vulnerable endpoint accepts GET requests rather than enforcing POST, the attacker can embed the delete action into a simple URL or a cross-origin form submission [1][3].
Impact
Successful exploitation allows the attacker to remove any or all configured Failure Causes in the plugin. This can degrade the ability of Jenkins to analyze build failures, potentially leading to undetected failures or misdiagnosis of build problems [2][4].
Mitigation
The vulnerability is fixed in Build Failure Analyzer Plugin version 2.4.2 [2]. Users are strongly advised to upgrade immediately. No workaround is available; enabling the Jenkins CSRF protection is insufficient because the vulnerable endpoint was explicitly missing the required POST restriction [1][3].
AI Insight generated on May 20, 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 |
|---|---|---|
com.sonyericsson.jenkins.plugins.bfa:build-failure-analyzerMaven | < 2.4.2 | 2.4.2 |
Affected products
2- Jenkins Project/Jenkins Build Failure Analyzer Pluginv5Range: 0
Patches
1a261229a67c5[SECURITY-3226][SECURITY-3239][SECURITY-3244]
5 files changed · +114 −1
src/main/java/com/sonyericsson/jenkins/plugins/bfa/AnnotationHelper.java+4 −1 modified@@ -23,6 +23,7 @@ */ package com.sonyericsson.jenkins.plugins.bfa; +import hudson.Functions; import java.io.Serializable; /** @@ -43,7 +44,9 @@ public class AnnotationHelper implements Serializable { */ public String getBefore() { if (!title.isEmpty()) { - return before + "<span style=\"color:white;background:red\" title=\"" + title + "\">"; + return before + + "<span style=\"color:white;background:red\" title=\"" + + Functions.htmlAttributeEscape(title) + "\">"; } else { return before; }
src/main/java/com/sonyericsson/jenkins/plugins/bfa/CauseManagement.java+2 −0 modified@@ -44,6 +44,7 @@ import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; import java.io.IOException; /** @@ -220,6 +221,7 @@ public FailureCause getDynamic(String id, StaplerRequest request, StaplerRespons * @param response the stapler response. * @throws IOException if so during redirect. */ + @POST public void doRemoveConfirm(@QueryParameter String id, StaplerRequest request, StaplerResponse response) throws IOException { Jenkins.getInstance().checkPermission(PluginImpl.REMOVE_PERMISSION);
src/main/java/com/sonyericsson/jenkins/plugins/bfa/db/MongoDBKnowledgeBase.java+3 −0 modified@@ -82,6 +82,7 @@ import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.verb.POST; import org.mongojack.JacksonMongoCollection; import org.mongojack.internal.MongoJackModule; @@ -868,6 +869,7 @@ public FormValidation doCheckDbName(@QueryParameter("value") String value) { * @return {@link FormValidation#ok() } if can be done, * {@link FormValidation#error(java.lang.String) } otherwise. */ + @POST public FormValidation doTestConnection( @QueryParameter("host") final String host, @QueryParameter("port") final int port, @@ -876,6 +878,7 @@ public FormValidation doTestConnection( @QueryParameter("password") final String password, @QueryParameter("tls") final boolean tls, @QueryParameter("retrywrites") final boolean retryWrites) { + Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); MongoDBKnowledgeBase base = new MongoDBKnowledgeBase(host, port, dbName, userName, Secret.fromString(password), false, false); base.setTls(tls);
src/test/java/com/sonyericsson/jenkins/plugins/bfa/CauseManagementPermissionTest.java+63 −0 modified@@ -1,17 +1,23 @@ package com.sonyericsson.jenkins.plugins.bfa; +import jenkins.model.Jenkins; import org.htmlunit.FailingHttpStatusCodeException; +import org.htmlunit.HttpMethod; +import org.htmlunit.WebRequest; import org.htmlunit.html.HtmlPage; import hudson.model.Hudson; import hudson.security.GlobalMatrixAuthorizationStrategy; import hudson.security.SecurityRealm; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import javax.servlet.http.HttpServletResponse; +import java.net.URL; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -24,6 +30,10 @@ */ public class CauseManagementPermissionTest { + private static final int EXPECTED_HTTP_NOT_FOUND_RESPONSE_CODE = 404; + private static final int EXPECTED_HTTP_FORBIDDEN_RESPONSE_CODE = 403; + private static final int EXPECTED_HTTP_SUCCESS_RESPONSE_CODE = 200; + /** * The Jenkins Rule. */ @@ -44,8 +54,11 @@ public void jenkinsConfiguration() { authorizationStrategy.add(Hudson.READ, "anonymous"); authorizationStrategy.add(PluginImpl.VIEW_PERMISSION, "view"); authorizationStrategy.add(PluginImpl.UPDATE_PERMISSION, "update"); + authorizationStrategy.add(PluginImpl.REMOVE_PERMISSION, "remove"); authorizationStrategy.add(PluginImpl.VIEW_PERMISSION, "all"); authorizationStrategy.add(PluginImpl.UPDATE_PERMISSION, "all"); + authorizationStrategy.add(PluginImpl.REMOVE_PERMISSION, "all"); + authorizationStrategy.add(Jenkins.ADMINISTER, "admin"); j.getInstance().setAuthorizationStrategy(authorizationStrategy); } @@ -128,4 +141,54 @@ public void allowedToUpdateCausesWhenGrantedBothUpdateAndView() throws Exception // Checks the "Create New" button is available assertNotNull(page.getFirstByXPath("//a[.='Create new']")); } + + /** + * Tests that removeConfirm only can be used with POST, and responds with 404 otherwise. + * + * @throws java.lang.Exception If Jenkins cannot be accessed + */ + @Issue("SECURITY-3239") + @Test + public void testDoRemoveConfirmRequiresPost() throws Exception { + JenkinsRule.WebClient webClient = j.createWebClient().withThrowExceptionOnFailingStatusCode(false); + webClient.login("all"); + assertEquals( + EXPECTED_HTTP_NOT_FOUND_RESPONSE_CODE, + webClient.goTo("failure-cause-management/removeConfirm").getWebResponse().getStatusCode()); + WebRequest webRequest = new WebRequest( + new URL(j.jenkins.getRootUrl().toString() + "/failure-cause-management/removeConfirm"), + HttpMethod.POST); + webRequest = webClient.addCrumb(webRequest); + assertEquals( + EXPECTED_HTTP_SUCCESS_RESPONSE_CODE, + webClient.getPage(webRequest).getWebResponse().getStatusCode()); + } + + /** + * Test that testing mongo connection can only be accessed through a POST request from an admin. + * + * @throws Exception if Jenkins cannot be accessed + */ + @Issue("SECURITY-3226") + @Test + public void testTestMongoDBConnection() throws Exception { + JenkinsRule.WebClient webClient = j.createWebClient().withThrowExceptionOnFailingStatusCode(false); + String testUrl = "descriptorByName/com.sonyericsson.jenkins.plugins.bfa.db.MongoDBKnowledgeBase/" + + "testConnection?port=9876&host=localhost&&dbName=Whatever\n"; + assertEquals( + EXPECTED_HTTP_NOT_FOUND_RESPONSE_CODE, + webClient.goTo(testUrl).getWebResponse().getStatusCode()); + webClient.login("all"); + WebRequest webRequest = new WebRequest( + new URL(j.jenkins.getRootUrl().toString() + testUrl), + HttpMethod.POST); + webRequest = webClient.addCrumb(webRequest); + assertEquals( + EXPECTED_HTTP_FORBIDDEN_RESPONSE_CODE, + webClient.getPage(webRequest).getWebResponse().getStatusCode()); + webClient.login("admin"); + assertEquals( + EXPECTED_HTTP_SUCCESS_RESPONSE_CODE, + webClient.getPage(webRequest).getWebResponse().getStatusCode()); + } }
src/test/java/com/sonyericsson/jenkins/plugins/bfa/IndicationAnnotatorTest.java+42 −0 added@@ -0,0 +1,42 @@ +package com.sonyericsson.jenkins.plugins.bfa; + +import static org.junit.Assert.assertTrue; + +import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause; +import com.sonyericsson.jenkins.plugins.bfa.model.FoundFailureCause; +import com.sonyericsson.jenkins.plugins.bfa.model.indication.FoundIndication; +import hudson.MarkupText; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import java.util.ArrayList; +import java.util.List; + +/** + * Tests for the IndicationAnnotator. + * + * @author Tomas Westling <tomas.westling@axis.com> + */ +public class IndicationAnnotatorTest { + + private static final String EXPECTED_ANNOTATED_TEXT = "tilt" onmouseover=alert(1) foo="bar"; + + /** + * Tests that html is escaped correctly when annotating text. + */ + @Issue("SECURITY-3244") + @Test + public void testAnnotate() { + MarkupText text = new MarkupText("matchingString"); + FoundIndication fi = new FoundIndication( + "pattern", "matchingFile", "matchingString"); + List<FoundIndication> fis = new ArrayList<>(); + fis.add(fi); + FoundFailureCause ffc = new FoundFailureCause( + new FailureCause("tilt\" onmouseover=alert(1) foo=\"bar", "description"), fis); + List<FoundFailureCause> foundFailureCauses = new ArrayList<>(); + foundFailureCauses.add(ffc); + IndicationAnnotator ia = new IndicationAnnotator(foundFailureCauses); + ia.annotate(null, text); + assertTrue(text.toString(false).indexOf(EXPECTED_ANNOTATED_TEXT) != -1); + } +}
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-2wwh-qgh8-w9xwghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-43502ghsaADVISORY
- www.jenkins.io/security/advisory/2023-09-20/ghsavendor-advisoryWEB
- www.openwall.com/lists/oss-security/2023/09/20/5ghsaWEB
- github.com/jenkinsci/build-failure-analyzer-plugin/commit/a261229a67c52927d531c48ec0a59bf138ebd4d0ghsaWEB
News mentions
1- Jenkins Security Advisory 2023-09-20Jenkins Security Advisories · Sep 20, 2023