VYPR
Low severityNVD Advisory· Published Sep 12, 2019· Updated Aug 4, 2024

CVE-2019-10398

CVE-2019-10398

Description

Jenkins Beaker Builder Plugin 1.9 and earlier stored credentials unencrypted in its global configuration file on the Jenkins master where they could be viewed by users with access to the master file system.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.jenkins-ci.plugins:beaker-builderMaven
< 1.101.10

Affected products

1

Patches

1
be0101f3541a

[FIX SECURITY-1545] Store credentials in encrypted form

4 files changed · +96 10
  • src/main/java/org/jenkinsci/plugins/beakerbuilder/BeakerBuilder.java+29 9 modified
    @@ -1,8 +1,10 @@
     package org.jenkinsci.plugins.beakerbuilder;
     
    +import com.google.common.annotations.VisibleForTesting;
     import hudson.Extension;
     import hudson.FilePath;
     import hudson.Launcher;
    +import hudson.XmlFile;
     import hudson.model.BuildListener;
     import hudson.model.Result;
     import hudson.model.AbstractBuild;
    @@ -12,6 +14,7 @@
     import hudson.util.FormValidation;
     
     import java.io.IOException;
    +import java.io.ObjectStreamException;
     import java.net.URL;
     import java.util.ArrayList;
     import java.util.Map;
    @@ -20,7 +23,9 @@
     import java.util.logging.Logger;
     
     import javax.annotation.CheckForNull;
    +import javax.annotation.Nonnull;
     
    +import hudson.util.Secret;
     import net.sf.json.JSONObject;
     
     import org.apache.xmlrpc.XmlRpcException;
    @@ -266,7 +271,6 @@ public static class DescriptorImpl extends BuildStepDescriptor<Builder> {
              */
             private String beakerURL;
     
    -        // TODO provide a way to store the credential in Jenkins authentication center.
             /**
              * Beaker login
              */
    @@ -275,7 +279,8 @@ public static class DescriptorImpl extends BuildStepDescriptor<Builder> {
             /**
              * Beaker password
              */
    -        private String password;
    +        private @Nonnull Secret secret;
    +        @Deprecated private String password;
     
             private transient BeakerClient beakerClient;
             private transient Identity identity;
    @@ -284,6 +289,15 @@ public DescriptorImpl() {
                 load();
             }
     
    +        private Object readResolve() {
    +            if (password != null) {
    +                secret = Secret.fromString(password);
    +                password = null;
    +                save();
    +            }
    +            return this;
    +        }
    +
             @Override
             public boolean isApplicable(@SuppressWarnings("rawtypes")Class<? extends AbstractProject> aClass) {
                 return true;
    @@ -318,8 +332,8 @@ public void setLogin(String login) {
             }
     
             @Restricted(DoNotUse.class) // Databinding
    -        public void setPassword(String password) {
    -            this.password = password;
    +        public void setPassword(Secret secret) {
    +            this.secret = secret;
             }
     
             /**
    @@ -331,7 +345,7 @@ private void setupClient() {
                     beakerClient = BeakerServer.getXmlRpcClient(beakerURL);
     
                     try {
    -                    identity = beakerClient.authenticate(new Identity(login, password));
    +                    identity = beakerClient.authenticate(new Identity(login, secret.getPlainText()));
                     } catch (XmlRpcException e) {
                         beakerClient = null;
                         LOGGER.log(Level.WARNING, "Unable to create beaker client", e);
    @@ -346,12 +360,12 @@ private void setupClient() {
             public FormValidation doTestConnection(
                     @QueryParameter("beakerURL") final String beakerURL,
                     @QueryParameter("login") final String login,
    -                @QueryParameter("password") final String password
    +                @QueryParameter("password") final Secret password
             ) {
                 LOGGER.fine("Trying to get client for " + beakerURL);
                 BeakerClient bc = BeakerServer.getXmlRpcClient(beakerURL);
                 try {
    -                Identity ident = bc.authenticate(new Identity(login, password));
    +                Identity ident = bc.authenticate(new Identity(login, password.getPlainText()));
     
                     return FormValidation.ok("Connected as " + ident.whoAmI());
                 } catch (Exception e) {
    @@ -367,8 +381,8 @@ public String getLogin() {
                 return login;
             }
     
    -        public String getPassword() {
    -            return password;
    +        public Secret getPassword() {
    +            return secret;
             }
     
             /**
    @@ -391,6 +405,12 @@ public String getPassword() {
                 setupClient();
                 return identity;
             }
    +
    +        @Override
    +        @VisibleForTesting
    +        protected XmlFile getConfigFile() {
    +            return super.getConfigFile();
    +        }
         }
     
         private static final Logger LOGGER = Logger.getLogger(BeakerBuilder.class.getName());
    
  • src/test/java/org/jenkinsci/plugins/beakerbuilder/ConfigRoundtripTest.java+19 1 modified
    @@ -32,11 +32,15 @@
     import org.jenkinsci.plugins.beakerbuilder.BeakerBuilder.DescriptorImpl;
     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.JenkinsRule.WebClient;
     
     import com.gargoylesoftware.htmlunit.html.HtmlForm;
     import com.gargoylesoftware.htmlunit.html.HtmlPage;
    +import org.jvnet.hudson.test.recipes.LocalData;
    +
    +import java.io.IOException;
     
     public class ConfigRoundtripTest {
     
    @@ -77,6 +81,20 @@ public void connectionRoundtrip() throws Exception {
     
             assertEquals("URL", descriptor.getBeakerURL());
             assertEquals("USERNAME", descriptor.getLogin());
    -        assertEquals("PASSWD", descriptor.getPassword());
    +        assertEquals("PASSWD", descriptor.getPassword().getPlainText());
    +    }
    +
    +    @Test
    +    @LocalData
    +    @Issue("SECURITY-1545")
    +    public void migratePasswordToSecret() throws IOException {
    +        DescriptorImpl descriptor = (DescriptorImpl) j.jenkins.getDescriptorOrDie(BeakerBuilder.class);
    +
    +        assertEquals("URL", descriptor.getBeakerURL());
    +        assertEquals("USERNAME", descriptor.getLogin());
    +        assertEquals("PASSWD", descriptor.getPassword().getPlainText());
    +
    +        String text = descriptor.getConfigFile().asString();
    +        assertFalse(text, text.contains("PASSWD"));
         }
     }
    
  • src/test/resources/org/jenkinsci/plugins/beakerbuilder/ConfigRoundtripTest/migratePasswordToSecret/config.xml+42 0 added
    @@ -0,0 +1,42 @@
    +<?xml version='1.0' encoding='UTF-8'?>
    +<hudson>
    +  <disabledAdministrativeMonitors/>
    +  <version>1.609.3</version>
    +  <numExecutors>2</numExecutors>
    +  <mode>NORMAL</mode>
    +  <useSecurity>true</useSecurity>
    +  <authorizationStrategy class="hudson.security.AuthorizationStrategy$Unsecured"/>
    +  <securityRealm class="hudson.security.SecurityRealm$None"/>
    +  <disableRememberMe>false</disableRememberMe>
    +  <projectNamingStrategy class="jenkins.model.ProjectNamingStrategy$DefaultProjectNamingStrategy"/>
    +  <workspaceDir>${JENKINS_HOME}/workspace/${ITEM_FULLNAME}</workspaceDir>
    +  <buildsDir>${ITEM_ROOTDIR}/builds</buildsDir>
    +  <jdks>
    +    <jdk>
    +      <name>default</name>
    +      <home>/usr/lib/jvm/java-7-openjdk/jre</home>
    +      <properties/>
    +    </jdk>
    +  </jdks>
    +  <viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
    +  <myViewsTabBar class="hudson.views.DefaultMyViewsTabBar"/>
    +  <clouds/>
    +  <quietPeriod>5</quietPeriod>
    +  <scmCheckoutRetryCount>0</scmCheckoutRetryCount>
    +  <views>
    +    <hudson.model.AllView>
    +      <owner class="hudson" reference="../../.."/>
    +      <name>All</name>
    +      <filterExecutors>false</filterExecutors>
    +      <filterQueue>false</filterQueue>
    +      <properties class="hudson.model.View$PropertyList"/>
    +    </hudson.model.AllView>
    +  </views>
    +  <primaryView>All</primaryView>
    +  <slaveAgentPort>0</slaveAgentPort>
    +  <label></label>
    +  <crumbIssuer class="org.jvnet.hudson.test.TestCrumbIssuer"/>
    +  <nodeProperties/>
    +  <globalNodeProperties/>
    +  <noUsageStatistics>true</noUsageStatistics>
    +</hudson>
    \ No newline at end of file
    
  • src/test/resources/org/jenkinsci/plugins/beakerbuilder/ConfigRoundtripTest/migratePasswordToSecret/org.jenkinsci.plugins.beakerbuilder.BeakerBuilder.xml+6 0 added
    @@ -0,0 +1,6 @@
    +<?xml version='1.0' encoding='UTF-8'?>
    +<org.jenkinsci.plugins.beakerbuilder.BeakerBuilder_-DescriptorImpl>
    +  <beakerURL>URL</beakerURL>
    +  <login>USERNAME</login>
    +  <password>PASSWD</password>
    +</org.jenkinsci.plugins.beakerbuilder.BeakerBuilder_-DescriptorImpl>
    \ No newline at end of file
    

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

5

News mentions

0

No linked articles in our index yet.