CVE-2020-2182
Description
Jenkins Credentials Binding Plugin 1.22 and earlier fails to mask secrets containing a '$' character due to improper escaping, allowing potential exposure in build logs.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Jenkins Credentials Binding Plugin 1.22 and earlier fails to mask secrets containing a '$' character due to improper escaping, allowing potential exposure in build logs.
Vulnerability
Description
Jenkins Credentials Binding Plugin 1.22 and earlier contains a flaw in how it masks secrets that include a $ character. The plugin, which allows specifying passwords and other secrets as environment variables, normally hides these values from console output during builds. However, as a side effect of a previous fix (SECURITY-698), the plugin escapes $ characters in secrets to $$. This escaped form is then expanded back to $ when the secret is passed to build steps, as described in the official advisory [1][2]. The vulnerability occurs because the plugin does not mask the escaped form (containing $$) of the secret, leading to potential exposure in build logs before value expansion.
Exploitation
Conditions
This issue manifests in scenarios where a secret contains a $ character and is used in a build step that performs variable expansion, such as the "Execute Maven top-level targets" build step included in Jenkins [1]. An attacker with the ability to view build logs (e.g., users with read access to job console output) could potentially observe the unredacted secret if it is displayed before expansion. No additional authentication beyond normal Jenkins access is required; the flaw is triggered during legitimate build operations [1][2].
Impact
An attacker who can access build console output may obtain sensitive secrets (e.g., passwords, API tokens) that were intended to be masked. This can lead to unauthorized access to systems or services protected by those credentials. The CVSS score is Low (3.1) due to the specific conditions required for exploitation, but the confidentiality impact is elevated when secrets are exposed [2].
Mitigation
Jenkins Credentials Binding Plugin version 1.23, released on 2020-05-06, resolves this issue by masking secrets both in their original form and with escaped $ characters [1][3]. The fix ensures that even if a secret is printed before value expansion, it remains hidden. Users should upgrade to version 1.23 or later, as indicated in the advisory [1][3].
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:credentials-bindingMaven | < 1.23 | 1.23 |
Affected products
2- Range: unspecified
Patches
177681e0d184b[SECURITY-1835]
2 files changed · +112 −0
src/main/java/org/jenkinsci/plugins/credentialsbinding/masking/DollarSecretPatternFactory.java+45 −0 added@@ -0,0 +1,45 @@ +/* + * The MIT License + * + * Copyright (c) 2020 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.jenkinsci.plugins.credentialsbinding.masking; + +import hudson.Extension; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.Collections; +import java.util.regex.Pattern; + +@Extension +@Restricted(NoExternalUse.class) +public class DollarSecretPatternFactory implements SecretPatternFactory { + @Override + public @Nonnull Collection<String> getEncodedForms(@Nonnull String input) { + return input.contains("$") + ? Collections.singleton(input.replace("$", "$$")) + : Collections.emptySet(); + } +}
src/test/java/org/jenkinsci/plugins/credentialsbinding/masking/DollarSecretPatternFactoryTest.java+67 −0 added@@ -0,0 +1,67 @@ +package org.jenkinsci.plugins.credentialsbinding.masking; + +import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.CredentialsScope; +import com.cloudbees.plugins.credentials.domains.Domain; +import hudson.Functions; +import hudson.model.FreeStyleBuild; +import hudson.model.FreeStyleProject; +import hudson.model.Item; +import hudson.model.queue.QueueTaskFuture; +import hudson.tasks.BatchFile; +import hudson.tasks.Maven; +import hudson.tasks.Shell; +import hudson.util.Secret; +import org.jenkinsci.plugins.credentialsbinding.impl.SecretBuildWrapper; +import org.jenkinsci.plugins.credentialsbinding.impl.StringBinding; +import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; + +import java.util.Arrays; + +public class DollarSecretPatternFactoryTest { + + @Rule + public JenkinsRule r = new JenkinsRule(); + + @Issue("JENKINS-24805") + @Test + public void maskingFreeStyleSecrets() throws Exception { + String firstCredentialsId = "creds_1"; + String firstPassword = "a$build"; + StringCredentialsImpl firstCreds = new StringCredentialsImpl(CredentialsScope.GLOBAL, firstCredentialsId, "sample1", Secret.fromString(firstPassword)); + + CredentialsProvider.lookupStores(r.jenkins).iterator().next().addCredentials(Domain.global(), firstCreds); + + String secondCredentialsId = "creds_2"; + String secondPassword = "a$$b"; + StringCredentialsImpl secondCreds = new StringCredentialsImpl(CredentialsScope.GLOBAL, secondCredentialsId, "sample2", Secret.fromString(secondPassword)); + + CredentialsProvider.lookupStores(r.jenkins).iterator().next().addCredentials(Domain.global(), secondCreds); + + SecretBuildWrapper wrapper = new SecretBuildWrapper(Arrays.asList(new StringBinding("PASS_1", firstCredentialsId), + new StringBinding("PASS_2", secondCredentialsId))); + + FreeStyleProject project = r.createFreeStyleProject(); + + project.setConcurrentBuild(true); + project.getBuildersList().add(Functions.isWindows() ? new BatchFile("echo %PASS_1%") : new Shell("echo \"$PASS_1\"")); + project.getBuildersList().add(Functions.isWindows() ? new BatchFile("echo %PASS_2%") : new Shell("echo \"$PASS_2\"")); + project.getBuildersList().add(new Maven("$PASS_1 $PASS_2", "default")); + project.getBuildWrappersList().add(wrapper); + + r.configRoundtrip((Item)project); + + QueueTaskFuture<FreeStyleBuild> future = project.scheduleBuild2(0); + FreeStyleBuild build = future.get(); + r.assertLogNotContains(firstPassword, build); + r.assertLogNotContains(firstPassword.replace("$", "$$"), build); + r.assertLogNotContains(secondPassword, build); + r.assertLogNotContains(secondPassword.replace("$", "$$"), build); + r.assertLogContains("****", build); + } + +}
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-7ff8-qfwx-8gx5ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-2182ghsaADVISORY
- www.openwall.com/lists/oss-security/2020/05/06/3ghsamailing-listx_refsource_MLISTWEB
- github.com/jenkinsci/credentials-binding-plugin/commit/77681e0d184b0ccafa2a27da3b3bdbba95b4fe8fghsaWEB
- jenkins.io/security/advisory/2020-05-06/ghsax_refsource_CONFIRMWEB
News mentions
1- Jenkins Security Advisory 2020-05-06Jenkins Security Advisories · May 6, 2020