VYPR
Moderate severityNVD Advisory· Published Oct 19, 2022· Updated May 8, 2025

CVE-2022-43419

CVE-2022-43419

Description

Jenkins Katalon Plugin 1.0.32 and earlier stores API keys unencrypted in job config.xml files, exposing them to users with Extended Read permission or file system access.

AI Insight

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

Jenkins Katalon Plugin 1.0.32 and earlier stores API keys unencrypted in job config.xml files, exposing them to users with Extended Read permission or file system access.

Vulnerability

Details

Jenkins Katalon Plugin versions 1.0.32 and earlier stores API keys in plaintext within job config.xml files on the Jenkins controller [1][4]. This occurs because the plugin does not use Jenkins' built-in credential storage mechanism, instead writing the API key directly into the job configuration XML [3]. As a result, the sensitive credential is persisted unencrypted on disk.

Exploitation

Prerequisites

An attacker must have either the Extended Read permission on a job or direct access to the Jenkins controller's file system to read the config.xml file [1][2]. No additional authentication is required beyond these permissions. The vulnerability is present in all jobs that use the Katalon Plugin to configure API keys.

Impact

Successful exploitation allows an attacker to retrieve the stored API key, which could be used to authenticate to the Katalon service and potentially access or modify test artifacts, configurations, or other resources associated with the Jenkins instance [4]. The severity is considered medium (CVSS 5.5) according to the Jenkins security advisory [1].

Mitigation

The issue is fixed in Katalon Plugin versions 1.0.33 and 1.0.34, which migrate to using Jenkins' encrypted credential store [2][3]. Users should upgrade immediately. There is no workaround other than restricting Extended Read permissions and file system access to trusted users.

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.

PackageAffected versionsPatched versions
org.jenkins-ci.plugins:katalonMaven
< 1.0.331.0.33

Affected products

2

Patches

1
64f819387f3f

Merge pull request #28 from katalon-studio/TES-948

https://github.com/jenkinsci/katalon-pluginDuy LuongOct 11, 2022via ghsa
2 files changed · +38 39
  • src/main/java/com/katalon/jenkins/plugin/ExecuteKatalonTestOpsPlan.java+10 39 modified
    @@ -1,15 +1,14 @@
     package com.katalon.jenkins.plugin;
     
     import com.cloudbees.plugins.credentials.CredentialsMatchers;
    -import com.cloudbees.plugins.credentials.CredentialsProvider;
     import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
    -import com.cloudbees.plugins.credentials.domains.DomainRequirement;
     import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
     import com.katalon.jenkins.plugin.entity.Plan;
     import com.katalon.jenkins.plugin.entity.Project;
     import com.katalon.jenkins.plugin.helper.KatalonTestOpsHelper;
     import com.katalon.jenkins.plugin.helper.KatalonTestOpsSearchHelper;
     import com.katalon.jenkins.plugin.helper.JenkinsLogger;
    +import com.katalon.jenkins.plugin.helper.SecurityHelper;
     import com.katalon.utils.Logger;
     import hudson.Extension;
     import hudson.FilePath;
    @@ -23,6 +22,7 @@
     import hudson.tasks.Builder;
     import hudson.util.FormValidation;
     import hudson.util.ListBoxModel;
    +import hudson.util.Secret;
     import jenkins.model.Jenkins;
     import jenkins.tasks.SimpleBuildStep;
     import net.sf.json.JSONObject;
    @@ -33,16 +33,12 @@
     
     import javax.annotation.Nonnull;
     import java.io.IOException;
    -import java.util.Collections;
    -import java.util.List;
     import java.util.UUID;
     
     public class ExecuteKatalonTestOpsPlan extends Builder implements SimpleBuildStep {
     
       private String credentialsId;
     
    -  private String apiKey;
    -
       private String plan;
     
       private String serverUrl;
    @@ -52,7 +48,6 @@ public class ExecuteKatalonTestOpsPlan extends Builder implements SimpleBuildSte
       @DataBoundConstructor
       public ExecuteKatalonTestOpsPlan(
           String credentialsId,
    -      String apiKey,
           String serverUrl,
           String projectId,
           String planId) {
    @@ -68,7 +63,6 @@ public ExecuteKatalonTestOpsPlan(
           this.serverUrl = serverUrl;
         }
         this.credentialsId = credentialsId;
    -    this.apiKey = apiKey;
         this.plan = planId;
         this.projectId = projectId;
       }
    @@ -81,14 +75,6 @@ public void setCredentialsId(String credentialsId) {
         this.credentialsId = credentialsId;
       }
     
    -  public String getApiKey() {
    -    return apiKey;
    -  }
    -
    -  public void setApiKey(String credentialsId) {
    -    this.apiKey = credentialsId;
    -  }
    -
       public String getServerUrl() {
         return serverUrl;
       }
    @@ -127,7 +113,8 @@ public void perform(@Nonnull Run<?, ?> run, @Nonnull FilePath filePath, @Nonnull
       private boolean doPerform(TaskListener taskListener) {
         Logger logger = new JenkinsLogger(taskListener);
         KatalonTestOpsHelper katalonAnalyticsHandler = new KatalonTestOpsHelper(logger);
    -    return katalonAnalyticsHandler.run(serverUrl, apiKey, plan, projectId);
    +    Secret apiKey = SecurityHelper.getApiKey(credentialsId);
    +    return katalonAnalyticsHandler.run(serverUrl, apiKey.getPlainText(), plan, projectId);
       }
     
       @Override
    @@ -161,20 +148,6 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc
           return super.configure(req, formData);
         }
     
    -    private String getApiKey(String credentialsId) {
    -      if (credentialsId == null) {
    -        return null;
    -      }
    -      List<StringCredentials> creds = CredentialsProvider.lookupCredentials(StringCredentials.class, Jenkins.getInstance(), ACL.SYSTEM, Collections.<DomainRequirement>emptyList());
    -      StringCredentials credentials = null;
    -      for (StringCredentials c : creds) {
    -        if (credentialsId.matches(c.getId())) {
    -          credentials = c;
    -        }
    -      }
    -      return credentials == null ? null : credentials.getSecret().getPlainText();
    -    }
    -
         public FormValidation doTestConnection(@QueryParameter("serverUrl") final String url,
                                                @QueryParameter("credentialsId") final String credentialsId) {
           if (url.isEmpty()) {
    @@ -185,14 +158,14 @@ public FormValidation doTestConnection(@QueryParameter("serverUrl") final String
             return FormValidation.error("Please select credentials.");
           }
     
    -      String apiKey = getApiKey(credentialsId);
    +      Secret apiKey = SecurityHelper.getApiKey(credentialsId);
           if (apiKey == null) {
             return FormValidation.error("Cannot get API key.");
           }
     
           try {
             KatalonTestOpsHelper katalonTestOpsHelper = new KatalonTestOpsHelper();
    -        String token = katalonTestOpsHelper.requestToken(url, apiKey);
    +        String token = katalonTestOpsHelper.requestToken(url, apiKey.getPlainText());
             if (token != null) {
               return FormValidation.ok("Success!");
             } else {
    @@ -214,11 +187,11 @@ public ListBoxModel doFillProjectIdItems(@QueryParameter("serverUrl") final Stri
           }
     
           ListBoxModel options = new ListBoxModel();
    -      String apiKey = getApiKey(credentialsId);
    +      Secret apiKey = SecurityHelper.getApiKey(credentialsId);
           if (apiKey != null) {
             KatalonTestOpsHelper katalonTestOpsHelper = new KatalonTestOpsHelper();
             try {
    -          String token = katalonTestOpsHelper.requestToken(url, apiKey);
    +          String token = katalonTestOpsHelper.requestToken(url, apiKey.getPlainText());
               if (token != null) {
                 KatalonTestOpsSearchHelper katalonTestOpsSearchHelper = new KatalonTestOpsSearchHelper();
                 Project[] projects = katalonTestOpsSearchHelper.getProjects(token, url);
    @@ -251,15 +224,15 @@ public ListBoxModel doFillPlanItems(@QueryParameter("serverUrl") final String ur
             return new ListBoxModel();
           }
     
    -      String apiKey = getApiKey(credentialsId);
    +      Secret apiKey = SecurityHelper.getApiKey(credentialsId);
           if (apiKey == null) {
             return new ListBoxModel();
           }
     
           ListBoxModel options = new ListBoxModel();
           KatalonTestOpsHelper katalonTestOpsHelper = new KatalonTestOpsHelper();
           try {
    -        String token = katalonTestOpsHelper.requestToken(url, apiKey);
    +        String token = katalonTestOpsHelper.requestToken(url, apiKey.getPlainText());
             if (token != null) {
               KatalonTestOpsSearchHelper katalonTestOpsSearchHelper = new KatalonTestOpsSearchHelper();
               Plan[] plans = katalonTestOpsSearchHelper.getPlan(token, url, projectId);
    @@ -325,10 +298,8 @@ public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item item,
         @Override
         public Builder newInstance(StaplerRequest req, JSONObject formData) throws FormException {
           String credentialsId = formData.getString("credentialsId");
    -      String apiKey = getApiKey(credentialsId);
           return new ExecuteKatalonTestOpsPlan(
               credentialsId,
    -          apiKey,
               formData.getString("serverUrl"),
               formData.getString("projectId"),
               formData.getString("plan"));
    
  • src/main/java/com/katalon/jenkins/plugin/helper/SecurityHelper.java+28 0 added
    @@ -0,0 +1,28 @@
    +package com.katalon.jenkins.plugin.helper;
    +
    +import com.cloudbees.plugins.credentials.CredentialsProvider;
    +import com.cloudbees.plugins.credentials.domains.DomainRequirement;
    +import hudson.security.ACL;
    +import hudson.util.Secret;
    +import jenkins.model.Jenkins;
    +import org.jenkinsci.plugins.plaincredentials.StringCredentials;
    +
    +import java.util.Collections;
    +import java.util.List;
    +
    +public class SecurityHelper {
    +
    +    public static Secret getApiKey(String credentialsId) {
    +        if (credentialsId == null) {
    +            return null;
    +        }
    +        List<StringCredentials> creds = CredentialsProvider.lookupCredentials(StringCredentials.class, Jenkins.getInstance(), ACL.SYSTEM, Collections.<DomainRequirement>emptyList());
    +        StringCredentials credentials = null;
    +        for (StringCredentials c : creds) {
    +            if (credentialsId.matches(c.getId())) {
    +                credentials = c;
    +            }
    +        }
    +        return credentials == null ? null : credentials.getSecret();
    +    }
    +}
    

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.