VYPR
Moderate severityNVD Advisory· Published Dec 17, 2019· Updated Aug 5, 2024

CVE-2019-16555

CVE-2019-16555

Description

A user-supplied regular expression in Jenkins Build Failure Analyzer Plugin 1.24.1 and earlier was processed in a way that wasn't interruptible, allowing attackers to have Jenkins evaluate a regular expression without the ability to interrupt this process.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Jenkins Build Failure Analyzer Plugin processes user-supplied regex without interruption, enabling potential denial of service.

Vulnerability

Overview

CVE-2019-16555 affects the Jenkins Build Failure Analyzer Plugin version 1.24.1 and earlier. The plugin accepts a regular expression from users and processes it in a way that cannot be interrupted. This means if a user supplies a specially crafted, resource-intensive regular expression (e.g., one vulnerable to catastrophic backtracking), Jenkins will evaluate it without any ability to stop the operation, potentially leading to a denial of service condition.

Exploitation

Scenario

An attacker with the ability to provide a regular expression to the plugin (any authenticated Jenkins user who can configure the plugin's build failure analysis) can submit a malicious regex. The vulnerability lies in the doMatchText method, which does not implement any timeout or interruption mechanism for regex evaluation. The plugin processes the regex on the Jenkins master, and there is no default limit on execution time for user-supplied regular expressions. The attack does not require special privileges beyond the ability to configure the plugin.

Impact

A successful exploit allows an attacker to cause the Jenkins master to hang or become unresponsive while processing the malicious regex. This can disrupt normal Jenkins operations, blocking builds, queue processing, and other critical functions. The impact is primarily a denial of service; no data confidentiality or integrity is directly compromised, but the availability of the Jenkins instance is severely affected.

Mitigation

The issue is fixed in Build Failure Analyzer Plugin version 1.24.2, released with the December 17, 2019 Jenkins security advisory [1][2]. The fix, visible in the commit at [4], introduces additional checks and likely implements a timeout or interruptible regex evaluation to prevent indefinite processing. Users should upgrade to version 1.24.2 or later immediately.

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.

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

Affected products

2

Patches

1
f316c885552a

[SECURITY-1651] Protect BuildLogIndication doMatchText

2 files changed · +109 1
  • src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/indication/BuildLogIndication.java+7 1 modified
    @@ -30,6 +30,7 @@
     import com.fasterxml.jackson.annotation.JsonProperty;
     import com.fasterxml.jackson.annotation.JsonTypeInfo;
     import com.sonyericsson.jenkins.plugins.bfa.Messages;
    +import com.sonyericsson.jenkins.plugins.bfa.PluginImpl;
     import com.sonyericsson.jenkins.plugins.bfa.model.BuildLogFailureReader;
     import com.sonyericsson.jenkins.plugins.bfa.model.FailureReader;
     import hudson.Extension;
    @@ -44,6 +45,7 @@
     import jenkins.model.Jenkins;
     import org.kohsuke.stapler.DataBoundConstructor;
     import org.kohsuke.stapler.QueryParameter;
    +import org.kohsuke.stapler.interceptor.RequirePOST;
     
     import java.io.IOException;
     import java.util.regex.Matcher;
    @@ -248,10 +250,12 @@ public String getDisplayName() {
              *         the string does not match the pattern,
              *         {@link FormValidation#error(java.lang.String) } otherwise.
              */
    +        @RequirePOST
             public FormValidation doMatchText(
                     @QueryParameter("pattern") final String testPattern,
                     @QueryParameter("testText") String testText,
                     @QueryParameter("textSourceIsUrl") final boolean textSourceIsUrl) {
    +            Jenkins.get().checkPermission(PluginImpl.UPDATE_PERMISSION);
                 if (textSourceIsUrl) {
                     testText = testText.replaceAll("/\\./", "/").replaceAll("/view/change-requests", "");
                     Matcher urlMatcher = URL_PATTERN.matcher(testText);
    @@ -332,7 +336,9 @@ && isValidBuildId(urlParts[2])) {
                     return FormValidation.error(Messages.InvalidURL_Error());
                 } else {
                     try {
    -                    if (testText.matches(testPattern)) {
    +                    final Pattern pattern = Pattern.compile(testPattern);
    +                    final Matcher matcher = pattern.matcher(new FailureReader.InterruptibleCharSequence(testText));
    +                    if (matcher.matches()) {
                             return FormValidation.ok(Messages.StringMatchesPattern());
                         }
                         return FormValidation.warning(Messages.StringDoesNotMatchPattern());
    
  • src/test/java/com/sonyericsson/jenkins/plugins/bfa/model/indication/BuildLogIndicationTest.java+102 0 modified
    @@ -24,7 +24,13 @@
      */
     package com.sonyericsson.jenkins.plugins.bfa.model.indication;
     
    +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
    +import com.gargoylesoftware.htmlunit.HttpMethod;
    +import com.gargoylesoftware.htmlunit.Page;
    +import com.gargoylesoftware.htmlunit.WebRequest;
    +import com.gargoylesoftware.htmlunit.util.UrlUtils;
     import com.sonyericsson.jenkins.plugins.bfa.Messages;
    +import com.sonyericsson.jenkins.plugins.bfa.PluginImpl;
     import com.sonyericsson.jenkins.plugins.bfa.model.BuildLogFailureReader;
     import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause;
     import com.sonyericsson.jenkins.plugins.bfa.model.FailureReader;
    @@ -39,21 +45,30 @@
     import hudson.model.Cause;
     import hudson.model.FreeStyleBuild;
     import hudson.model.FreeStyleProject;
    +import hudson.model.Item;
     import hudson.model.Result;
    +import hudson.security.SecurityRealm;
     import hudson.util.FormValidation;
    +import jenkins.model.Jenkins;
     import org.junit.Rule;
     import org.junit.Test;
    +import org.jvnet.hudson.test.Issue;
    +import org.jvnet.hudson.test.JenkinsRule;
    +import org.jvnet.hudson.test.MockAuthorizationStrategy;
     import org.jvnet.hudson.test.MockBuilder;
     
     import java.io.BufferedReader;
    +import java.io.IOException;
     import java.util.ArrayList;
     import java.util.List;
     import java.util.concurrent.Future;
     import java.util.concurrent.TimeUnit;
     
    +import static org.hamcrest.Matchers.is;
     import static org.junit.Assert.assertEquals;
     import static org.junit.Assert.assertNotNull;
     import static org.junit.Assert.assertNull;
    +import static org.junit.Assert.assertThat;
     
     /**
      * Tests for the BuildLogIndication.
    @@ -276,4 +291,91 @@ public void testDoMatchTextUrlInvalid() {
             assertEquals(Messages.InvalidURL_Error(), formValidation.getMessage());
             assertEquals(FormValidation.Kind.ERROR, formValidation.kind);
         }
    +
    +    // CS IGNORE MagicNumber FOR NEXT 200 LINES. REASON: test data.
    +
    +    @Test @Issue("SECURITY-1651")
    +    public void testDoMatchNotHttpGetAccessible() throws Exception {
    +        lockDown();
    +        final JenkinsRule.WebClient webClient = j.createWebClient();
    +        webClient.assertFails("descriptorByName/"
    +                + BuildLogIndication.class.getName()
    +                + "/matchText?"
    +                + "pattern=[a-z]+&"
    +                + "testText=hello&"
    +                + "textSourceIsUrl=false",
    +                405);
    +    }
    +
    +    @Test @Issue("SECURITY-1651")
    +    public void testDoMatchHttpPostAccessible() throws Exception {
    +        lockDown();
    +        final JenkinsRule.WebClient webClient = j.createWebClient();
    +        post(webClient, "descriptorByName/"
    +                        + BuildLogIndication.class.getName()
    +                        + "/matchText?"
    +                        + "pattern=[a-z]+&"
    +                        + "testText=hello&"
    +                        + "textSourceIsUrl=false",
    +                null, 403);
    +    }
    +
    +    @Test @Issue("SECURITY-1651")
    +    public void testDoMatchHttpPostAccessibleWithPermission() throws Exception {
    +        lockDown();
    +        final JenkinsRule.WebClient webClient = j.createWebClient().login("bob");
    +        post(webClient, "descriptorByName/"
    +                        + BuildLogIndication.class.getName()
    +                        + "/matchText?"
    +                        + "pattern=[a-z]+&"
    +                        + "testText=hello&"
    +                        + "textSourceIsUrl=false",
    +                null, null);
    +    }
    +
    +    /**
    +     * Performs an HTTP POST request to the relative url.
    +     *
    +     * @param webClient the client
    +     * @param relative the url relative to the context path
    +     * @param expectedContentType if expecting specific content type or null if not
    +     * @param expectedStatus if expecting a failing http status code or null if not
    +     * @throws IOException if so
    +     */
    +    private static void post(JenkinsRule.WebClient webClient, String relative,
    +                             String expectedContentType, Integer expectedStatus) throws IOException {
    +        WebRequest request = new WebRequest(
    +                UrlUtils.toUrlUnsafe(webClient.getContextPath() + relative),
    +                HttpMethod.POST);
    +        try {
    +            Page p = webClient.getPage(request);
    +            if (expectedContentType != null) {
    +                assertThat(p.getWebResponse().getContentType(), is(expectedContentType));
    +            }
    +        } catch (FailingHttpStatusCodeException e) {
    +            if (expectedStatus != null) {
    +                assertEquals(expectedStatus.intValue(), e.getStatusCode());
    +            } else {
    +                throw e;
    +            }
    +        }
    +    }
    +
    +    /**
    +     * Lock down the instance.
    +     */
    +    private void lockDown() {
    +        SecurityRealm securityRealm = j.createDummySecurityRealm();
    +        j.getInstance().setSecurityRealm(securityRealm);
    +        j.getInstance().setAuthorizationStrategy(
    +                new MockAuthorizationStrategy().grant(Jenkins.READ).everywhere().toAuthenticated());
    +        j.jenkins.setCrumbIssuer(null); //Not really testing csrf right now
    +        j.getInstance().setAuthorizationStrategy(
    +                new MockAuthorizationStrategy().grant(Item.READ, Item.DISCOVER).everywhere().toAuthenticated()
    +                        .grant(PluginImpl.VIEW_PERMISSION).everywhere().toAuthenticated()
    +                        .grant(Jenkins.READ, Item.DISCOVER).everywhere().toEveryone()
    +                        .grant(Item.CONFIGURE).everywhere().to("bob")
    +                        .grant(PluginImpl.UPDATE_PERMISSION).everywhere().to("bob")
    +                        .grant(Jenkins.ADMINISTER).everywhere().to("alice"));
    +    }
     }
    

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

0

No linked articles in our index yet.