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

CVE-2023-43494

CVE-2023-43494

Description

Jenkins 2.50 through 2.423 (both inclusive), LTS 2.60.1 through 2.414.1 (both inclusive) does not exclude sensitive build variables (e.g., password parameter values) from the search in the build history widget, allowing attackers with Item/Read permission to obtain values of sensitive variables used in builds by iteratively testing different characters until the correct sequence is discovered.

AI Insight

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

Sensitive build variable values can be recovered via search in Jenkins build history widget by attackers with Item/Read permission.

Vulnerability

Overview

CVE-2023-43494 affects Jenkins core versions 2.50 through 2.423 and LTS 2.60.1 through 2.414.1. The build history widget allows filtering builds by an expression that searches for matching builds by name, description, parameter values, etc. However, Jenkins does not exclude sensitive build variables (e.g., password parameter values) from this search [1][2].

Exploitation

An attacker with Item/Read permission can leverage this flaw to obtain values of sensitive variables used in builds. By iteratively testing different characters in the search field (similar to a blind oracle attack), the attacker can discover the exact sequence of a sensitive variable's value, such as a password, by observing which builds match the search criteria [1][2].

Impact

Successful exploitation allows an attacker with only read-level access to retrieve the plaintext values of sensitive build parameters, which may include passwords, API tokens, or other credentials used during builds. This information can then be used to escalate privileges or compromise downstream systems [1][2].

Mitigation

Jenkins 2.424 and LTS 2.414.2 exclude sensitive variables from the build history search, fixing the vulnerability [2][4]. Users are strongly advised to upgrade to these or later versions. The fix was introduced in commit b8ac8cd [4].

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
org.jenkins-ci.main:jenkins-coreMaven
>= 2.50, < 2.414.22.414.2
org.jenkins-ci.main:jenkins-coreMaven
>= 2.415, < 2.4242.424

Affected products

3

Patches

1
b8ac8cd4c515

[SECURITY-3261]

https://github.com/jenkinsci/jenkinsDaniel BeckSep 6, 2023via ghsa
3 files changed · +133 2
  • core/src/main/java/jenkins/widgets/HistoryPageFilter.java+4 2 modified
    @@ -42,6 +42,7 @@
     import java.util.LinkedList;
     import java.util.List;
     import java.util.Map;
    +import java.util.Set;
     import jenkins.model.queue.QueueItem;
     
     /**
    @@ -371,8 +372,9 @@ private boolean fitsSearchString(Object data) {
     
         private boolean fitsSearchBuildVariables(AbstractBuild<?, ?> runAsBuild) {
             Map<String, String> buildVariables = runAsBuild.getBuildVariables();
    -        for (String paramsValues : buildVariables.values()) {
    -            if (fitsSearchString(paramsValues)) {
    +        Set<String> sensitiveBuildVariables = runAsBuild.getSensitiveBuildVariables();
    +        for (Map.Entry<String, String> param : buildVariables.entrySet()) {
    +            if (!sensitiveBuildVariables.contains(param.getKey()) && fitsSearchString(param.getValue())) {
                     return true;
                 }
             }
    
  • core/src/test/java/jenkins/widgets/HistoryPageFilterTest.java+7 0 modified
    @@ -43,6 +43,7 @@
     import java.util.Collections;
     import java.util.List;
     import java.util.Map;
    +import java.util.Set;
     import java.util.stream.Collectors;
     import jenkins.model.queue.QueueItem;
     import org.junit.Assert;
    @@ -485,6 +486,7 @@ private static class MockBuild extends Build<FreeStyleProject, FreeStyleBuild> {
             private final int buildNumber;
     
             private Map<String, String> buildVariables = Collections.emptyMap();
    +        private Set<String> sensitiveBuildVariables = Collections.emptySet();
     
             private MockBuild(int buildNumber) {
                 super(Mockito.mock(FreeStyleProject.class), Mockito.mock(Calendar.class));
    @@ -501,6 +503,11 @@ public Map<String, String> getBuildVariables() {
                 return buildVariables;
             }
     
    +        @Override
    +        public Set<String> getSensitiveBuildVariables() {
    +            return sensitiveBuildVariables; // TODO This is never actually set (bad Mock), actual test in test harness
    +        }
    +
             MockBuild withBuildVariables(Map<String, String> buildVariables) {
                 this.buildVariables = buildVariables;
                 return this;
    
  • test/src/test/java/jenkins/widgets/HistoryPageFilterTest.java+122 0 added
    @@ -0,0 +1,122 @@
    +package jenkins.widgets;
    +
    +import static org.hamcrest.MatcherAssert.assertThat;
    +import static org.hamcrest.Matchers.contains;
    +import static org.hamcrest.Matchers.empty;
    +
    +import hudson.model.AbstractBuild;
    +import hudson.model.FreeStyleBuild;
    +import hudson.model.FreeStyleProject;
    +import hudson.model.ParametersAction;
    +import hudson.model.ParametersDefinitionProperty;
    +import hudson.model.PasswordParameterDefinition;
    +import hudson.model.StringParameterDefinition;
    +import hudson.tasks.BuildWrapper;
    +import hudson.util.Secret;
    +import java.util.HashMap;
    +import java.util.HashSet;
    +import java.util.Map;
    +import java.util.Objects;
    +import java.util.Set;
    +import java.util.stream.Collectors;
    +import org.junit.Rule;
    +import org.junit.Test;
    +import org.jvnet.hudson.test.JenkinsRule;
    +
    +
    +public class HistoryPageFilterTest {
    +    @Rule
    +    public JenkinsRule j = new JenkinsRule();
    +
    +    @Test
    +    public void doNotFindSensitiveBuildParams() throws Exception {
    +        final FreeStyleProject freeStyleProject = j.createFreeStyleProject();
    +        final PasswordParameterDefinition passwordParameterDefinition = new PasswordParameterDefinition("password", Secret.fromString("t0ps3cr3t"), "description");
    +        final StringParameterDefinition stringParameterDefinition = new StringParameterDefinition("key", "value", "desc");
    +        freeStyleProject.addProperty(new ParametersDefinitionProperty(passwordParameterDefinition, stringParameterDefinition));
    +        final FreeStyleBuild build1 = j.buildAndAssertSuccess(freeStyleProject);
    +        final FreeStyleBuild build2 = j.waitForCompletion(Objects.requireNonNull(freeStyleProject.scheduleBuild2(
    +                0,
    +                new ParametersAction(
    +                        passwordParameterDefinition.createValue("p4ssw0rd"),
    +                        stringParameterDefinition.createValue("value123"))))
    +                .waitForStart());
    +        {
    +            final HistoryPageFilter<FreeStyleBuild> historyPageFilter = new HistoryPageFilter<>(30);
    +            historyPageFilter.setSearchString("value");
    +            historyPageFilter.add(freeStyleProject.getBuilds());
    +            assertThat(historyPageFilter.runs.stream().map(HistoryPageEntry::getEntry).collect(Collectors.toList()), contains(build2, build1));
    +            assertThat(historyPageFilter.queueItems, empty());
    +        }
    +        {
    +            final HistoryPageFilter<FreeStyleBuild> historyPageFilter = new HistoryPageFilter<>(30);
    +            historyPageFilter.setSearchString("t0p");
    +            historyPageFilter.add(freeStyleProject.getBuilds());
    +            assertThat(historyPageFilter.runs, empty());
    +            assertThat(historyPageFilter.queueItems, empty());
    +        }
    +        {
    +            final HistoryPageFilter<FreeStyleBuild> historyPageFilter = new HistoryPageFilter<>(30);
    +            historyPageFilter.setSearchString("value123");
    +            historyPageFilter.add(freeStyleProject.getBuilds());
    +            assertThat(historyPageFilter.runs.stream().map(HistoryPageEntry::getEntry).collect(Collectors.toList()), contains(build2));
    +            assertThat(historyPageFilter.queueItems, empty());
    +        }
    +        {
    +            final HistoryPageFilter<FreeStyleBuild> historyPageFilter = new HistoryPageFilter<>(30);
    +            historyPageFilter.setSearchString("p4ss");
    +            historyPageFilter.add(freeStyleProject.getBuilds());
    +            assertThat(historyPageFilter.runs, empty());
    +            assertThat(historyPageFilter.queueItems, empty());
    +        }
    +    }
    +
    +    @Test
    +    public void doNotFindSensitiveBuildWrapperVars() throws Exception {
    +        final FreeStyleProject freeStyleProject = j.createFreeStyleProject();
    +        freeStyleProject.getBuildWrappersList().add(new BuildWrapperWithSomeSensitiveVars(Map.of("key1", "value123", "key2", "value234", "key3", "s3cr3t"), Set.of("key3")));
    +        final FreeStyleBuild build = j.buildAndAssertSuccess(freeStyleProject);
    +        {
    +            final HistoryPageFilter<FreeStyleBuild> historyPageFilter = new HistoryPageFilter<>(30);
    +            historyPageFilter.setSearchString("value");
    +            historyPageFilter.add(freeStyleProject.getBuilds());
    +            assertThat(historyPageFilter.runs.stream().map(HistoryPageEntry::getEntry).collect(Collectors.toList()), contains(build));
    +            assertThat(historyPageFilter.queueItems, empty());
    +        }
    +        {
    +            final HistoryPageFilter<FreeStyleBuild> historyPageFilter = new HistoryPageFilter<>(30);
    +            historyPageFilter.setSearchString("value123");
    +            historyPageFilter.add(freeStyleProject.getBuilds());
    +            assertThat(historyPageFilter.runs.stream().map(HistoryPageEntry::getEntry).collect(Collectors.toList()), contains(build));
    +            assertThat(historyPageFilter.queueItems, empty());
    +        }
    +        {
    +            final HistoryPageFilter<FreeStyleBuild> historyPageFilter = new HistoryPageFilter<>(30);
    +            historyPageFilter.setSearchString("s3cr3t");
    +            historyPageFilter.add(freeStyleProject.getBuilds());
    +            assertThat(historyPageFilter.runs, empty());
    +            assertThat(historyPageFilter.queueItems, empty());
    +        }
    +    }
    +
    +    private static class BuildWrapperWithSomeSensitiveVars extends BuildWrapper {
    +        private final Map<String, String> variables;
    +        private final Set<String> sensitiveVariables;
    +
    +        private BuildWrapperWithSomeSensitiveVars(Map<String, String> variables, Set<String> sensitiveVariables) {
    +
    +            this.variables = new HashMap<>(variables);
    +            this.sensitiveVariables = new HashSet<>(sensitiveVariables);
    +        }
    +
    +        @Override
    +        public void makeBuildVariables(AbstractBuild build, Map<String, String> variables) {
    +            variables.putAll(this.variables);
    +        }
    +
    +        @Override
    +        public void makeSensitiveBuildVariables(AbstractBuild build, Set<String> sensitiveVariables) {
    +            sensitiveVariables.addAll(this.sensitiveVariables);
    +        }
    +    }
    +}
    

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