VYPR
Moderate severityNVD Advisory· Published Aug 7, 2019· Updated Aug 4, 2024

CVE-2019-10367

CVE-2019-10367

Description

Due to an incomplete fix of CVE-2019-10343, Jenkins Configuration as Code Plugin 1.26 and earlier did not properly apply masking to some values expected to be hidden when logging the configuration being applied.

AI Insight

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

Jenkins Configuration as Code Plugin 1.26 and earlier fails to mask secrets in a specific log message, partially undoing a previous fix.

Vulnerability

Details

CVE-2019-10367 is an incomplete fix for CVE-2019-10343 in the Jenkins Configuration as Code Plugin (versions 1.26 and earlier). The plugin logs configuration changes to the system log, and while a prior fix attempted to mask secrets like passwords by inspecting field types and property mappings, it missed coverage for log messages written to the logger io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator [1].

Exploitation and

Attack Surface

An attacker with access to Jenkins system logs—for instance, a user who can read log files or a malicious insider—could observe secret values (e.g., passwords, API tokens) that were inadvertently printed in plain text. No special network position or authentication bypass is required beyond log access; the flaw lies entirely in the logging behavior, not in direct remote exploitation [1][2].

Impact

Exposure of credentials could lead to privilege escalation, lateral movement, or compromise of integrated systems, depending on the leaked secrets. Because the plugin is commonly used to manage Jenkins configuration as code, the leaked values might include highly sensitive credentials for cloud providers, source control, or other CI/CD services [1][3].

Mitigation

Users should upgrade to Configuration as Code Plugin 1.27 or later, which applies consistent secret masking across all loggers. As a workaround, administrators can reduce the logging level of io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator to a level that does not include these messages (INFO-level messages are no longer logged in version 1.26 but were present in earlier releases) [1][4].

AI Insight generated on May 22, 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
io.jenkins:configuration-as-codeMaven
< 1.271.27

Affected products

2

Patches

1
322ef83f3200

[SECURITY-1497]

3 files changed · +63 5
  • plugin/src/main/java/io/jenkins/plugins/casc/Attribute.java+4 3 modified
    @@ -1,6 +1,5 @@
     package io.jenkins.plugins.casc;
     
    -import com.google.common.annotations.VisibleForTesting;
     import hudson.util.Secret;
     import io.jenkins.plugins.casc.model.CNode;
     import io.jenkins.plugins.casc.model.Scalar;
    @@ -27,6 +26,8 @@
     import org.apache.commons.collections.CollectionUtils;
     import org.apache.commons.lang.StringUtils;
     import org.kohsuke.accmod.AccessRestriction;
    +import org.kohsuke.accmod.Restricted;
    +import org.kohsuke.accmod.restrictions.NoExternalUse;
     import org.kohsuke.stapler.export.Exported;
     
     import static io.jenkins.plugins.casc.ConfigurationAsCode.printThrowable;
    @@ -329,8 +330,8 @@ private static Field locatePrivateFieldInHierarchy(Class<?> clazz, @Nonnull Stri
          * @return {@code true} if the attribute is secret
          *         {@code false} if not or if there is no conclusive answer.
          */
    -    @VisibleForTesting
    -    /*package*/ static boolean calculateIfSecret(@CheckForNull Class<?> targetClass, @Nonnull String fieldName) {
    +    @Restricted(NoExternalUse.class)
    +    public static boolean calculateIfSecret(@CheckForNull Class<?> targetClass, @Nonnull String fieldName) {
             if (targetClass == Secret.class) { // Class is final, so the check is safe
                 LOGGER.log(Level.FINER, "Attribute {0}#{1} is secret, because it has a Secret type",
                         new Object[] {targetClass.getName(), fieldName});
    
  • plugin/src/main/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfigurator.java+4 2 modified
    @@ -160,8 +160,10 @@ private T tryConstructor(Constructor<T> constructor, Mapping config, Configurati
                             final Configurator configurator = context.lookupOrFail(k);
                             args[i] = configurator.configure(value, context);
                         }
    -                    LOGGER.log(Level.FINE, "Setting {0}. {1} = {2}",
    -                        new Object[] {target, names[i], t == Secret.class ? "****" : value});
    +                    if (LOGGER.isLoggable(Level.FINE)) {
    +                        LOGGER.log(Level.FINE, "Setting {0}. {1} = {2}",
    +                                new Object[]{target, names[i], t == Secret.class || Attribute.calculateIfSecret(target, names[i]) ? "****" : value});
    +                    }
                     } else if (t.isPrimitive()) {
                         args[i] = defaultValue(t);
                     }
    
  • plugin/src/test/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfiguratorTest.java+55 0 modified
    @@ -1,5 +1,6 @@
     package io.jenkins.plugins.casc.impl.configurators;
     
    +import hudson.util.Secret;
     import io.jenkins.plugins.casc.ConfigurationAsCode;
     import io.jenkins.plugins.casc.ConfigurationContext;
     import io.jenkins.plugins.casc.Configurator;
    @@ -15,15 +16,21 @@
     import io.jenkins.plugins.casc.model.Sequence;
     import java.util.HashSet;
     import java.util.Set;
    +import java.util.logging.Level;
    +import java.util.logging.Logger;
     import javax.annotation.ParametersAreNonnullByDefault;
     import javax.annotation.PostConstruct;
    +import org.junit.Before;
     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.LoggerRule;
     import org.kohsuke.stapler.DataBoundConstructor;
     import org.kohsuke.stapler.DataBoundSetter;
     
    +import static io.jenkins.plugins.casc.misc.Util.assertNotInLog;
    +import static io.jenkins.plugins.casc.misc.Util.assertLogContains;
     import static io.jenkins.plugins.casc.misc.Util.getJenkinsRoot;
     import static org.hamcrest.Matchers.is;
     import static org.junit.Assert.assertEquals;
    @@ -41,6 +48,14 @@ public class DataBoundConfiguratorTest {
         @Rule
         public JenkinsRule j = new JenkinsRule();
     
    +    @Rule
    +    public LoggerRule logging = new LoggerRule();
    +
    +    @Before
    +    public void tearUp() {
    +        logging.record(Logger.getLogger(DataBoundConfigurator.class.getName()), Level.FINEST).capture(2048);
    +    }
    +
         @Test
         public void configure_databound() throws Exception {
             Mapping config = new Mapping();
    @@ -208,6 +223,27 @@ public void shouldThrowConfiguratorException() {
             }
         }
     
    +    @Test
    +    public void shouldNotLogSecrets() throws Exception {
    +        Mapping config = new Mapping();
    +        config.put("secret", "mySecretValue");
    +        ConfiguratorRegistry registry = ConfiguratorRegistry.get();
    +        registry.lookupOrFail(SecretHolder.class).configure(config, new ConfigurationContext(registry));
    +        assertLogContains(logging, "secret");
    +        assertNotInLog(logging, "mySecretValue");
    +    }
    +
    +    @Test
    +    @Issue("SECURITY-1497")
    +    public void shouldNotLogSecretsForUndefinedConstructors() throws Exception {
    +        Mapping config = new Mapping();
    +        config.put("secret", "mySecretValue");
    +        ConfiguratorRegistry registry = ConfiguratorRegistry.get();
    +        registry.lookupOrFail(SecretHolderWithString.class).configure(config, new ConfigurationContext(registry));
    +        assertLogContains(logging, "secret");
    +        assertNotInLog(logging, "mySecretValue");
    +    }
    +
         public static class Foo {
     
             final String foo;
    @@ -287,4 +323,23 @@ public Set<String> getStrings() {
             }
         }
     
    +    public static class SecretHolder {
    +
    +        Secret secret;
    +
    +        @DataBoundConstructor
    +        public SecretHolder(Secret secret) {
    +            this.secret = secret;
    +        }
    +    }
    +
    +    public static class SecretHolderWithString {
    +
    +        Secret secret;
    +
    +        @DataBoundConstructor
    +        public SecretHolderWithString(String secret) {
    +            this.secret = Secret.fromString(secret);
    +        }
    +    }
     }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.