Low severityNVD Advisory· Published Jan 12, 2022· Updated Aug 3, 2024
CVE-2022-23114
CVE-2022-23114
Description
Jenkins Publish Over SSH Plugin 1.22 and earlier stores password unencrypted in its global configuration file on the Jenkins controller where it can be viewed by users with access to the Jenkins controller file system.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.jenkins-ci.plugins:publish-over-sshMaven | < 1.23 | 1.23 |
Affected products
1- Range: unspecified
Patches
22b4b9b2dfab5Merge pull request #52 from olamy/SECURITY-2291
4 files changed · +49 −31
src/main/java/jenkins/plugins/publish_over_ssh/BapSshHostConfiguration.java+39 −20 modified@@ -30,8 +30,10 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Objects; import java.util.Properties; +import hudson.util.Secret; import jenkins.model.Jenkins; import jenkins.plugins.publish_over.*; import jenkins.plugins.publish_over_ssh.descriptor.BapSshHostConfigurationDescriptor; @@ -70,7 +72,10 @@ public class BapSshHostConfiguration extends BPHostConfiguration<BapSshClient, B private String proxyHost; private int proxyPort; private String proxyUser; + + @Deprecated private String proxyPassword; + private Secret secretProxyPassword; public BapSshHostConfiguration() { // use this constructor instead of the default w/o parameters because there is some @@ -183,7 +188,13 @@ public void setEncryptedPassword(final String encryptedPassword) { public String getProxyUser() { return proxyUser; } - public String getProxyPassword() {return proxyPassword; } + public String getProxyPassword() { + return Secret.toString(this.secretProxyPassword); + } + + public Secret getSecretProxyPassword() { + return this.secretProxyPassword; + } @DataBoundSetter public void setProxyType(String proxyType) { @@ -207,7 +218,21 @@ public void setProxyUser(String proxyUser) { @DataBoundSetter public void setProxyPassword(String proxyPassword) { - this.proxyPassword = proxyPassword; + this.secretProxyPassword = Secret.fromString(proxyPassword); + } + + @DataBoundSetter + public void setSecretProxyPassword(Secret secretProxyPassword) { + this.secretProxyPassword = secretProxyPassword; + } + + @Override + public Object readResolve() { + if(StringUtils.isNotEmpty(proxyPassword)) { + this.secretProxyPassword = Secret.fromString(this.proxyPassword); + this.proxyPassword = null; + } + return super.readResolve(); } public boolean isEffectiveDisableExec() { @@ -251,13 +276,7 @@ public BapSshClient createClient(final BPBuildInfo buildInfo, final boolean conn } if (connectSftp) setupSftp(bapClient); - } catch (IOException e) { - bapClient.disconnectQuietly(); - throw new BapPublisherException(Messages.exception_failedToCreateClient(e.getLocalizedMessage()), e); - } catch (JSchException e) { - bapClient.disconnectQuietly(); - throw new BapPublisherException(Messages.exception_failedToCreateClient(e.getLocalizedMessage()), e); - } catch (BapPublisherException e) { + } catch (IOException | JSchException | BapPublisherException e) { bapClient.disconnectQuietly(); throw new BapPublisherException(Messages.exception_failedToCreateClient(e.getLocalizedMessage()), e); } @@ -284,7 +303,7 @@ static String[] getHosts(String target, String jumpHosts) { } } hosts.add(target); - return hosts.toArray(new String[hosts.size()]); + return hosts.toArray(new String[0]); } } @@ -395,24 +414,24 @@ private Session createSession(final BPBuildInfo buildInfo, final JSch ssh, Strin if (StringUtils.isNotEmpty(proxyType) && StringUtils.isNotEmpty(proxyHost)) { if (StringUtils.equals(HTTP_PROXY_TYPE, proxyType)) { ProxyHTTP proxyHTTP = new ProxyHTTP(proxyHost, proxyPort); - if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(proxyPassword)) { - proxyHTTP.setUserPasswd(proxyUser, proxyPassword); + if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(secretProxyPassword.getPlainText())) { + proxyHTTP.setUserPasswd(proxyUser, secretProxyPassword.getPlainText()); } else { proxyHTTP.setUserPasswd(null, null); } session.setProxy(proxyHTTP); } else if (StringUtils.equals(SOCKS_4_PROXY_TYPE, proxyType)) { ProxySOCKS4 proxySocks4 = new ProxySOCKS4(proxyHost, proxyPort); - if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(proxyPassword)) { - proxySocks4.setUserPasswd(proxyUser, proxyPassword); + if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(secretProxyPassword.getPlainText())) { + proxySocks4.setUserPasswd(proxyUser, secretProxyPassword.getPlainText()); } else { proxySocks4.setUserPasswd(null, null); } session.setProxy(proxySocks4); } else if (StringUtils.equals(SOCKS_5_PROXY_TYPE, proxyType)) { ProxySOCKS5 proxySocks5 = new ProxySOCKS5(proxyHost, proxyPort); - if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(proxyPassword)) { - proxySocks5.setUserPasswd(proxyUser, proxyPassword); + if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(secretProxyPassword.getPlainText())) { + proxySocks5.setUserPasswd(proxyUser, secretProxyPassword.getPlainText()); } else { proxySocks5.setUserPasswd(null, null); } @@ -435,7 +454,7 @@ protected JSch createJSch() { } public BapSshHostConfigurationDescriptor getDescriptor() { - return Jenkins.getInstance().getDescriptorByType(BapSshHostConfigurationDescriptor.class); + return Jenkins.get().getDescriptorByType(BapSshHostConfigurationDescriptor.class); } protected EqualsBuilder addToEquals(final EqualsBuilder builder, final BapSshHostConfiguration that) { @@ -449,7 +468,7 @@ protected EqualsBuilder addToEquals(final EqualsBuilder builder, final BapSshHos .append(proxyHost, that.proxyHost) .append(proxyPort, that.proxyPort) .append(proxyUser, that.proxyUser) - .append(proxyPassword, that.proxyPassword); + .append(secretProxyPassword, that.secretProxyPassword); } @Override @@ -464,7 +483,7 @@ protected HashCodeBuilder addToHashCode(final HashCodeBuilder builder) { .append(proxyHost) .append(proxyPort) .append(proxyUser) - .append(proxyPassword); + .append(secretProxyPassword.getPlainText()); } @Override @@ -479,7 +498,7 @@ protected ToStringBuilder addToToString(final ToStringBuilder builder) { .append("proxyHost", proxyHost) .append("proxyPort", proxyPort) .append("proxyUser", proxyUser) - .append("proxyPassword", proxyPassword); + .append("proxyPassword", "xxxxxxx"); } @Override
src/main/java/jenkins/plugins/publish_over_ssh/descriptor/BapSshHostConfigurationDescriptor.java+0 −1 modified@@ -101,5 +101,4 @@ public FormValidation doTestConnection(final StaplerRequest request, final Stapl public jenkins.plugins.publish_over.view_defaults.HostConfiguration.Messages getCommonFieldNames() { return new jenkins.plugins.publish_over.view_defaults.HostConfiguration.Messages(); } - }
src/main/java/jenkins/plugins/publish_over_ssh/descriptor/BapSshPublisherPluginDescriptor.java+9 −9 modified@@ -29,6 +29,13 @@ import java.util.Comparator; import java.util.List; +import hudson.Extension; +import hudson.ExtensionPoint; +import hudson.init.InitMilestone; +import hudson.init.Initializer; +import hudson.util.Secret; +import jenkins.plugins.publish_over.BPHostConfiguration; +import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -67,7 +74,7 @@ public class BapSshPublisherPluginDescriptor extends BuildStepDescriptor<Publish /** null - prevent complaints from xstream */ @SuppressFBWarnings(value = "URF_UNREAD_FIELD") private transient Class hostConfigClass; - private final CopyOnWriteList<BapSshHostConfiguration> hostConfigurations = new CopyOnWriteList<BapSshHostConfiguration>(); + private final CopyOnWriteList<BapSshHostConfiguration> hostConfigurations = new CopyOnWriteList<>(); private BapSshCommonConfiguration commonConfig; private SshDefaults defaults; @@ -101,14 +108,7 @@ public List<BapSshHostConfiguration> getHostConfigurations() { retVal.add(current); } - Collections.sort(retVal, new Comparator<BapSshHostConfiguration>() { - - @Override - public int compare(BapSshHostConfiguration p1, BapSshHostConfiguration p2) { - return p1.getName().compareTo(p2.getName()); - } - - }); + Collections.sort(retVal, Comparator.comparing(BPHostConfiguration::getName)); return retVal; }
src/main/resources/jenkins/plugins/publish_over_ssh/BapSshHostConfiguration/config.jelly+1 −1 modified@@ -86,7 +86,7 @@ <f:entry title="${%proxyUser}" field="proxyUser"> <f:textbox/> </f:entry> - <f:entry title="${%proxyPassword}" field="proxyPassword"> + <f:entry title="${%proxyPassword}" field="secretProxyPassword"> <f:password/> </f:entry>
70b7689bf6fc[SECURITY-2291] Unprotected Storage of Credentials
4 files changed · +49 −31
src/main/java/jenkins/plugins/publish_over_ssh/BapSshHostConfiguration.java+39 −20 modified@@ -30,8 +30,10 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Objects; import java.util.Properties; +import hudson.util.Secret; import jenkins.model.Jenkins; import jenkins.plugins.publish_over.*; import jenkins.plugins.publish_over_ssh.descriptor.BapSshHostConfigurationDescriptor; @@ -70,7 +72,10 @@ public class BapSshHostConfiguration extends BPHostConfiguration<BapSshClient, B private String proxyHost; private int proxyPort; private String proxyUser; + + @Deprecated private String proxyPassword; + private Secret secretProxyPassword; public BapSshHostConfiguration() { // use this constructor instead of the default w/o parameters because there is some @@ -183,7 +188,13 @@ public void setEncryptedPassword(final String encryptedPassword) { public String getProxyUser() { return proxyUser; } - public String getProxyPassword() {return proxyPassword; } + public String getProxyPassword() { + return Secret.toString(this.secretProxyPassword); + } + + public Secret getSecretProxyPassword() { + return this.secretProxyPassword; + } @DataBoundSetter public void setProxyType(String proxyType) { @@ -207,7 +218,21 @@ public void setProxyUser(String proxyUser) { @DataBoundSetter public void setProxyPassword(String proxyPassword) { - this.proxyPassword = proxyPassword; + this.secretProxyPassword = Secret.fromString(proxyPassword); + } + + @DataBoundSetter + public void setSecretProxyPassword(Secret secretProxyPassword) { + this.secretProxyPassword = secretProxyPassword; + } + + @Override + public Object readResolve() { + if(StringUtils.isNotEmpty(proxyPassword)) { + this.secretProxyPassword = Secret.fromString(this.proxyPassword); + this.proxyPassword = null; + } + return super.readResolve(); } public boolean isEffectiveDisableExec() { @@ -251,13 +276,7 @@ public BapSshClient createClient(final BPBuildInfo buildInfo, final boolean conn } if (connectSftp) setupSftp(bapClient); - } catch (IOException e) { - bapClient.disconnectQuietly(); - throw new BapPublisherException(Messages.exception_failedToCreateClient(e.getLocalizedMessage()), e); - } catch (JSchException e) { - bapClient.disconnectQuietly(); - throw new BapPublisherException(Messages.exception_failedToCreateClient(e.getLocalizedMessage()), e); - } catch (BapPublisherException e) { + } catch (IOException | JSchException | BapPublisherException e) { bapClient.disconnectQuietly(); throw new BapPublisherException(Messages.exception_failedToCreateClient(e.getLocalizedMessage()), e); } @@ -284,7 +303,7 @@ static String[] getHosts(String target, String jumpHosts) { } } hosts.add(target); - return hosts.toArray(new String[hosts.size()]); + return hosts.toArray(new String[0]); } } @@ -395,24 +414,24 @@ private Session createSession(final BPBuildInfo buildInfo, final JSch ssh, Strin if (StringUtils.isNotEmpty(proxyType) && StringUtils.isNotEmpty(proxyHost)) { if (StringUtils.equals(HTTP_PROXY_TYPE, proxyType)) { ProxyHTTP proxyHTTP = new ProxyHTTP(proxyHost, proxyPort); - if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(proxyPassword)) { - proxyHTTP.setUserPasswd(proxyUser, proxyPassword); + if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(secretProxyPassword.getPlainText())) { + proxyHTTP.setUserPasswd(proxyUser, secretProxyPassword.getPlainText()); } else { proxyHTTP.setUserPasswd(null, null); } session.setProxy(proxyHTTP); } else if (StringUtils.equals(SOCKS_4_PROXY_TYPE, proxyType)) { ProxySOCKS4 proxySocks4 = new ProxySOCKS4(proxyHost, proxyPort); - if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(proxyPassword)) { - proxySocks4.setUserPasswd(proxyUser, proxyPassword); + if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(secretProxyPassword.getPlainText())) { + proxySocks4.setUserPasswd(proxyUser, secretProxyPassword.getPlainText()); } else { proxySocks4.setUserPasswd(null, null); } session.setProxy(proxySocks4); } else if (StringUtils.equals(SOCKS_5_PROXY_TYPE, proxyType)) { ProxySOCKS5 proxySocks5 = new ProxySOCKS5(proxyHost, proxyPort); - if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(proxyPassword)) { - proxySocks5.setUserPasswd(proxyUser, proxyPassword); + if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(secretProxyPassword.getPlainText())) { + proxySocks5.setUserPasswd(proxyUser, secretProxyPassword.getPlainText()); } else { proxySocks5.setUserPasswd(null, null); } @@ -435,7 +454,7 @@ protected JSch createJSch() { } public BapSshHostConfigurationDescriptor getDescriptor() { - return Jenkins.getInstance().getDescriptorByType(BapSshHostConfigurationDescriptor.class); + return Jenkins.get().getDescriptorByType(BapSshHostConfigurationDescriptor.class); } protected EqualsBuilder addToEquals(final EqualsBuilder builder, final BapSshHostConfiguration that) { @@ -449,7 +468,7 @@ protected EqualsBuilder addToEquals(final EqualsBuilder builder, final BapSshHos .append(proxyHost, that.proxyHost) .append(proxyPort, that.proxyPort) .append(proxyUser, that.proxyUser) - .append(proxyPassword, that.proxyPassword); + .append(secretProxyPassword, that.secretProxyPassword); } @Override @@ -464,7 +483,7 @@ protected HashCodeBuilder addToHashCode(final HashCodeBuilder builder) { .append(proxyHost) .append(proxyPort) .append(proxyUser) - .append(proxyPassword); + .append(secretProxyPassword.getPlainText()); } @Override @@ -479,7 +498,7 @@ protected ToStringBuilder addToToString(final ToStringBuilder builder) { .append("proxyHost", proxyHost) .append("proxyPort", proxyPort) .append("proxyUser", proxyUser) - .append("proxyPassword", proxyPassword); + .append("proxyPassword", "xxxxxxx"); } @Override
src/main/java/jenkins/plugins/publish_over_ssh/descriptor/BapSshHostConfigurationDescriptor.java+0 −1 modified@@ -99,5 +99,4 @@ public FormValidation doTestConnection(final StaplerRequest request, final Stapl public jenkins.plugins.publish_over.view_defaults.HostConfiguration.Messages getCommonFieldNames() { return new jenkins.plugins.publish_over.view_defaults.HostConfiguration.Messages(); } - }
src/main/java/jenkins/plugins/publish_over_ssh/descriptor/BapSshPublisherPluginDescriptor.java+9 −9 modified@@ -29,6 +29,13 @@ import java.util.Comparator; import java.util.List; +import hudson.Extension; +import hudson.ExtensionPoint; +import hudson.init.InitMilestone; +import hudson.init.Initializer; +import hudson.util.Secret; +import jenkins.plugins.publish_over.BPHostConfiguration; +import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -66,7 +73,7 @@ public class BapSshPublisherPluginDescriptor extends BuildStepDescriptor<Publish /** null - prevent complaints from xstream */ @SuppressFBWarnings(value = "URF_UNREAD_FIELD") private transient Class hostConfigClass; - private final CopyOnWriteList<BapSshHostConfiguration> hostConfigurations = new CopyOnWriteList<BapSshHostConfiguration>(); + private final CopyOnWriteList<BapSshHostConfiguration> hostConfigurations = new CopyOnWriteList<>(); private BapSshCommonConfiguration commonConfig; private SshDefaults defaults; @@ -100,14 +107,7 @@ public List<BapSshHostConfiguration> getHostConfigurations() { retVal.add(current); } - Collections.sort(retVal, new Comparator<BapSshHostConfiguration>() { - - @Override - public int compare(BapSshHostConfiguration p1, BapSshHostConfiguration p2) { - return p1.getName().compareTo(p2.getName()); - } - - }); + Collections.sort(retVal, Comparator.comparing(BPHostConfiguration::getName)); return retVal; }
src/main/resources/jenkins/plugins/publish_over_ssh/BapSshHostConfiguration/config.jelly+1 −1 modified@@ -86,7 +86,7 @@ <f:entry title="${%proxyUser}" field="proxyUser"> <f:textbox/> </f:entry> - <f:entry title="${%proxyPassword}" field="proxyPassword"> + <f:entry title="${%proxyPassword}" field="secretProxyPassword"> <f:password/> </f:entry>
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-r3rr-wph6-9638ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-23114ghsaADVISORY
- www.openwall.com/lists/oss-security/2022/01/12/6ghsamailing-listx_refsource_MLISTWEB
- github.com/jenkinsci/publish-over-ssh-plugin/commit/2b4b9b2dfab5c001669f9a74c0e6078b0a27b928ghsaWEB
- github.com/jenkinsci/publish-over-ssh-plugin/commit/70b7689bf6fc894f4dc6c0ff34dd72808840760eghsaWEB
- github.com/jenkinsci/publish-over-ssh-plugin/releases/tag/publish-over-ssh-1.23ghsaWEB
- www.jenkins.io/security/advisory/2022-01-12/ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.