CVE-2022-28146
Description
Jenkins Continuous Integration with Toad Edge Plugin 2.3 and earlier allows attackers with Item/Configure permission to read arbitrary files on the Jenkins controller by specifying an input folder parameter in build steps.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Jenkins Continuous Integration with Toad Edge Plugin 2.3 and earlier allows attackers with Item/Configure permission to read arbitrary files on the Jenkins controller by specifying an input folder parameter in build steps.
Vulnerability
Jenkins Continuous Integration with Toad Edge Plugin version 2.3 and earlier does not restrict the input folder parameter in its build steps [1][4]. Attackers with Item/Configure permission can specify any folder path on the Jenkins controller, leading to arbitrary file read [1][4].
Exploitation
An attacker with Item/Configure permission can configure a build step to use an arbitrary folder path as the input parameter [1][4]. No additional authentication or user interaction is required beyond having the permission [1][4].
Impact
Successful exploitation allows the attacker to read arbitrary files from the Jenkins controller file system [1][4]. This can expose sensitive information such as credentials, secrets, or configuration files [1][4].
Mitigation
The vulnerability is fixed in Continuous Integration with Toad Edge Plugin version 2.4, released on March 29, 2022 [2][3]. Users should upgrade to version 2.4 or later [2][3]. No workarounds are available for older versions [1][2].
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:ci-with-toad-edgeMaven | < 2.4 | 2.4 |
Affected products
2- Jenkins project/Jenkins Continuous Integration with Toad Edge Pluginv5Range: unspecified
Patches
149d4b855773e{SECURITY-2633}
24 files changed · +115 −96
src/main/java/ci/with/toad/edge/CompareBuilder.java+13 −0 modified@@ -130,6 +130,19 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen System.setOut(listener.getLogger()); System.setErr(listener.getLogger()); + FormValidation checkValidation = FormValidationUtil.restrictLocation(srcInputFileOrFolder, build); + if(checkValidation != FormValidation.ok()) { + throw new Error(checkValidation.getMessage()); + } + FormValidation checkValidationTarget = FormValidationUtil.restrictLocation(tgtInputFileOrFolder, build); + if(checkValidationTarget != FormValidation.ok()) { + throw new Error(checkValidationTarget.getMessage()); + } + FormValidation checkValidationConfig=FormValidationUtil.restrictLocation(configFile, build); + if(checkValidationConfig != FormValidation.ok()){ + throw new Error(checkValidationConfig.getMessage()); + } + copyBuildFiles(build, listener); ensureTmpOutputFolder(build, listener);
src/main/java/ci/with/toad/edge/CompareWithBaselineBuilder.java+13 −0 modified@@ -128,6 +128,19 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen System.setOut(listener.getLogger()); System.setErr(listener.getLogger()); + FormValidation checkValidation = FormValidationUtil.restrictLocation(srcInputFileOrFolder, build); + if(checkValidation != FormValidation.ok()) { + throw new Error(checkValidation.getMessage()); + } + FormValidation checkValidationTarget = FormValidationUtil.restrictLocation(tgtInputFileOrFolder, build); + if(checkValidationTarget != FormValidation.ok()) { + throw new Error(checkValidationTarget.getMessage()); + } + FormValidation checkValidationConfig=FormValidationUtil.restrictLocation(configFile, build); + if(checkValidationConfig != FormValidation.ok()){ + throw new Error(checkValidationConfig.getMessage()); + } + copyBuildFiles(build, listener); ensureTmpOutputFolder(build, listener);
src/main/java/ci/with/toad/edge/CreateBaselineBuilder.java+6 −1 modified@@ -88,7 +88,12 @@ private FilePath getTmpOutput(AbstractBuild<?, ?> build) throws IOException, Int public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { System.setOut(listener.getLogger()); System.setErr(listener.getLogger()); - + + FormValidation checkValidation = FormValidationUtil.restrictLocation(inputFileOrFolder, build); + if(checkValidation != FormValidation.ok()) { + throw new Error(checkValidation.getMessage()); + } + copyBuildFiles(build, listener); Map<String, String> arguments = new HashMap<>();
src/main/java/ci/with/toad/edge/CreateSnapshotBuilder.java+6 −1 modified@@ -89,7 +89,12 @@ private FilePath getTmpOutput(AbstractBuild<?, ?> build) throws IOException, Int public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { System.setOut(listener.getLogger()); System.setErr(listener.getLogger()); - + + FormValidation checkValidation = FormValidationUtil.restrictLocation(inputFileOrFolder, build); + if( checkValidation != FormValidation.ok()) { + throw new Error(checkValidation.getMessage()); + } + copyBuildFiles(build, listener); Map<String, String> arguments = new HashMap<>();
src/main/java/ci/with/toad/edge/DeployScriptBuilder.java+9 −0 modified@@ -87,6 +87,15 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen System.setOut(listener.getLogger()); System.setErr(listener.getLogger()); + FormValidation checkValidation = FormValidationUtil.restrictLocation(in, build); + if( checkValidation != FormValidation.ok()) { + throw new Error(checkValidation.getMessage()); + } + FormValidation checkValidationOut = FormValidationUtil.restrictLocation(out, build); + if(checkValidationOut != FormValidation.ok()) { + throw new Error(checkValidation.getMessage()); + } + copyBuildFiles(build, listener); Map<String, String> arguments = new HashMap<>();
src/main/java/ci/with/toad/edge/FormValidationUtil.java+33 −0 modified@@ -16,11 +16,19 @@ */ package ci.with.toad.edge; +import hudson.FilePath; +import hudson.model.AbstractBuild; import org.jvnet.localizer.Localizable; import org.jvnet.localizer.ResourceBundleHolder; import hudson.util.FormValidation; +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URL; + public class FormValidationUtil { /** @@ -35,4 +43,29 @@ public static FormValidation doCheckEmptyValue(String value, String fieldName) { } return FormValidation.ok(); } + + /** + * Checks if folder path is in current workspace path + * + * @param folderPath + * @return + */ + @Nonnull + public static FormValidation restrictLocation(String folderPath, AbstractBuild<?, ?> build) throws IOException, InterruptedException { + final FilePath workspaceDir = build.getWorkspace(); + final FilePath inputDir = FileUtils.getFilePath(build,folderPath); + if(workspaceDir == null) { + return FormValidation.ok(); + } + final String inputDirLocation = inputDir.toURI().getPath(); + final String workspaceDirLocation = workspaceDir.toURI().getPath(); + + if(workspaceDir.isRemote() != inputDir.isRemote()) { + return FormValidation.error(String.format("Input folder: %s needs to be in the job's agent node", inputDirLocation)); + } + if(inputDirLocation.contains(workspaceDirLocation)) { + return FormValidation.ok(); + } + return FormValidation.error(String.format("Specified folder or file (%s) should be inside project workspace directory",inputDirLocation)); + } }
src/main/java/ci/with/toad/edge/GenerateChangeScriptBuilder.java+6 −1 modified@@ -82,7 +82,12 @@ private FilePath getTmpOut(AbstractBuild<?, ?> build) { public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { System.setOut(listener.getLogger()); System.setErr(listener.getLogger()); - + + FormValidation checkValidation = FormValidationUtil.restrictLocation(in, build); + if(checkValidation != FormValidation.ok()) { + throw new Error(checkValidation.getMessage()); + } + copyBuildFiles(build, listener); Map<String, String> arguments = new HashMap<>();
src/main/java/ci/with/toad/edge/GenerateCreateScriptBuilder.java+6 −1 modified@@ -89,7 +89,12 @@ private FilePath getTmpOutput(AbstractBuild<?, ?> build) { public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { System.setOut(listener.getLogger()); System.setErr(listener.getLogger()); - + + FormValidation checkValidation = FormValidationUtil.restrictLocation(inputFileOrFolder, build); + if(checkValidation != FormValidation.ok()){ + throw new Error(checkValidation.getMessage()); + } + copyBuildFiles(build, listener); Map<String, String> arguments = new HashMap<>();
src/main/java/ci/with/toad/edge/GenerateJenkinsReportBuilder.java+5 −0 modified@@ -84,6 +84,11 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen System.setOut(listener.getLogger()); System.setErr(listener.getLogger()); + FormValidation checkValidation = FormValidationUtil.restrictLocation(inputFolder, build); + if(checkValidation != FormValidation.ok()) { + throw new Error(checkValidation.getMessage()); + } + copyBuildFiles(build, listener); FilePath tmpOutput = getTmpOut(build); tmpOutput.mkdirs();
src/main/java/ci/with/toad/edge/GenerateStandaloneReportBuilder.java+4 −0 modified@@ -85,6 +85,10 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen System.setOut(listener.getLogger()); System.setErr(listener.getLogger()); + FormValidation checkValidation = FormValidationUtil.restrictLocation(inputFolder, build); + if(checkValidation != FormValidation.ok()) { + throw new Error(checkValidation.getMessage()); + } copyBuildFiles(build, listener); FilePath tmpOutput = getTmpOut(build); tmpOutput.mkdirs();
src/main/resources/ci/with/toad/edge/CompareBuilder/help-configFile.html+1 −4 modified@@ -8,10 +8,7 @@ File location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/CompareBuilder/help-srcInputFileOrFolder.html+1 −7 modified@@ -13,13 +13,7 @@ Folder/file location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/CompareBuilder/help-tgtInputFileOrFolder.html+1 −7 modified@@ -13,13 +13,7 @@ Folder/file location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/CompareWithBaselineBuilder/help-configFile.html+1 −4 modified@@ -8,10 +8,7 @@ File location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/CompareWithBaselineBuilder/help-srcInputFileOrFolder.html+1 −7 modified@@ -13,13 +13,7 @@ Folder/file location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/CompareWithBaselineBuilder/help-tgtInputFileOrFolder.html+1 −7 modified@@ -13,13 +13,7 @@ Folder/file location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/CreateBaselineBuilder/help-inputFileOrFolder.html+1 −7 modified@@ -12,13 +12,7 @@ Folder/file location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/CreateSnapshotBuilder/help-inputFileOrFolder.html+1 −7 modified@@ -12,13 +12,7 @@ Folder/file location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/DeployScriptBuilder/help-in.html+1 −7 modified@@ -8,13 +8,7 @@ File location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}file or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}file. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/DeployScriptBuilder/help-out.html+1 −7 modified@@ -8,13 +8,7 @@ File location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}file or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}file. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/GenerateChangeScriptBuilder/help-in.html+1 −7 modified@@ -9,13 +9,7 @@ Folder location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/GenerateCreateScriptBuilder/help-inputFileOrFolder.html+1 −7 modified@@ -13,13 +13,7 @@ Folder/file location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/GenerateJenkinsReportBuilder/help-inputFolder.html+1 −7 modified@@ -8,13 +8,7 @@ Folder location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
src/main/resources/ci/with/toad/edge/GenerateStandaloneReportBuilder/help-inputFolder.html+1 −7 modified@@ -8,13 +8,7 @@ Folder location must be specified as: <ul> <li> - Absolute path to location on your Jenkins master node - </li> - <li> - Relative path to your project's workspace. Either starting with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. - </li> - <li> - Relative path to your job's run root directory. It must start with ${JOB_ROOT_DIR} prefix. i.e. ${JOB_ROOT_DIR}dir. + Relative or absolute path to your project's workspace. Relative path should start with ${WORKSPACE} prefix. i.e. ${WORKSPACE}dir or without prefix i.e. dir. </li> </ul> </p>
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-8p4x-fq8v-xhv4ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-28146ghsaADVISORY
- www.openwall.com/lists/oss-security/2022/03/29/1ghsamailing-listx_refsource_MLISTWEB
- github.com/jenkinsci/ci-with-toad-edge-plugin/commit/49d4b855773ed4bbc58fc510149ec24d504f80d4ghsaWEB
- www.jenkins.io/security/advisory/2022-03-29/ghsax_refsource_CONFIRMWEB
News mentions
1- Jenkins Security Advisory 2022-03-29Jenkins Security Advisories · Mar 29, 2022