VYPR
Moderate severityNVD Advisory· Published Sep 20, 2023· Updated Sep 24, 2024

CVE-2023-43502

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.

PackageAffected versionsPatched versions
com.sonyericsson.jenkins.plugins.bfa:build-failure-analyzerMaven
< 2.4.22.4.2

Affected products

2

Patches

1
a261229a67c5

[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 &lt;tomas.westling@axis.com&gt;
    + */
    +public class IndicationAnnotatorTest {
    +
    +    private static final String EXPECTED_ANNOTATED_TEXT = "tilt&quot; onmouseover=alert(1) foo=&quot;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

News mentions

1