CSRF vulnerability in Fortify Plugin allow capturing credentials
Description
A CSRF vulnerability in Jenkins Fortify Plugin 22.1.38 and earlier allows attackers to use a crafted request to connect to an attacker-controlled URL with attacker-specified credentials, potentially capturing stored Jenkins credentials.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A CSRF vulnerability in Jenkins Fortify Plugin 22.1.38 and earlier allows attackers to use a crafted request to connect to an attacker-controlled URL with attacker-specified credentials, potentially capturing stored Jenkins credentials.
Vulnerability
Overview
A cross-site request forgery (CSRF) vulnerability exists in the Jenkins Fortify Plugin versions 22.1.38 and earlier [3]. The plugin fails to require POST requests for certain HTTP endpoints, specifically those performing validation checks like doCheckUrl, doCheckSscTokenCredentialsId, and doCheckCtrlUrl [1]. This missing CSRF protection allows an attacker to trick an authenticated Jenkins user into executing unintended actions without their knowledge.
Exploitation
Prerequisites
To exploit this vulnerability, an attacker must be able to trick a Jenkins user with sufficient permissions into visiting a malicious webpage [2]. The attacker also needs to have already obtained credentials IDs through another method (e.g., information disclosure or social engineering) [3]. The vulnerability is triggered when the victim performs actions that invoke the unprotected form validation endpoints, causing the plugin to connect to an attacker-specified URL using the attacker-provided credentials ID.
Impact
Successful exploitation allows an attacker to connect to an arbitrary URL using attacker-specified credentials IDs. This can lead to the capture or leakage of credentials stored in Jenkins, as the connection is made using those credentials [3]. The impact is considered high (CVSS 3.1 score 8.8) because it can result in credential theft, potentially enabling further compromise of the Jenkins environment and connected systems [2].
Mitigation
The Jenkins Fortify Plugin version 22.1.39 addresses this vulnerability by adding @POST annotations to the affected form validation methods, ensuring they only respond to POST requests and thus preventing CSRF attacks [1]. Users are advised to upgrade to version 22.1.39 or later immediately. There are no known workarounds for this vulnerability [2].
AI Insight generated on May 20, 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:fortifyMaven | < 22.2.39 | 22.2.39 |
Affected products
2- Range: 0
Patches
1357d7bfbcb0fSECURITY-3115, SECURITY-3139, SECURITY-3140, SECURITY-3141
7 files changed · +222 −95
src/main/java/com/fortify/plugin/jenkins/FortifyPlugin.java+133 −45 modified@@ -41,6 +41,7 @@ import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; import com.cloudbees.plugins.credentials.Credentials; import com.cloudbees.plugins.credentials.CredentialsMatchers; @@ -1253,6 +1254,7 @@ public FormValidation doCheckBreakdownPageSize(@QueryParameter String value) { return FormValidation.ok(); } + @POST public FormValidation doCheckUrl(@QueryParameter String value) { try { checkUrlValue(value == null ? null : value.trim()); @@ -1262,13 +1264,15 @@ public FormValidation doCheckUrl(@QueryParameter String value) { return FormValidation.ok(); } + @POST public FormValidation doCheckSscTokenCredentialsId(@QueryParameter String value, @QueryParameter String url) { if (StringUtils.isBlank(value) && (StringUtils.isNotBlank(url) && doCheckUrl(url) == FormValidation.ok())) { return FormValidation.warning("Authentication token cannot be empty"); } return FormValidation.ok(); } + @POST public FormValidation doCheckCtrlTokenCredentialsId(@QueryParameter String value, @QueryParameter String ctrlUrl) { if (StringUtils.isBlank(value) && StringUtils.isNotBlank(ctrlUrl)) { return FormValidation.warning("Controller token cannot be empty"); @@ -1288,7 +1292,9 @@ public FormValidation doCheckFpr(@QueryParameter String value) { } } + @POST public FormValidation doCheckProjectTemplate(@QueryParameter String value) { + checkAdministerPermission(); try { checkProjectTemplateName(value.trim()); } catch (FortifyException e) { @@ -1337,6 +1343,7 @@ public FormValidation doCheckPollingInterval(@QueryParameter String value) { } } + @POST public FormValidation doCheckCtrlUrl(@QueryParameter String value, @QueryParameter String url) { if (StringUtils.isBlank(value)) { if (StringUtils.isNotBlank(url) && (doCheckUrl(url) == FormValidation.ok())) { @@ -1353,6 +1360,7 @@ public FormValidation doCheckCtrlUrl(@QueryParameter String value, @QueryParamet return FormValidation.ok(); } + @POST public ListBoxModel doFillSscTokenCredentialsIdItems(@AncestorInPath Item item, @QueryParameter String sscTokenCredentialsId, @QueryParameter String url) { StandardListBoxModel result = new StandardListBoxModel(); if (item == null) { @@ -1368,8 +1376,14 @@ public ListBoxModel doFillSscTokenCredentialsIdItems(@AncestorInPath Item item, .includeMatchingAs(ACL.SYSTEM, item, FortifyApiToken.class, URIRequirementBuilder.fromUri(url).build(), CredentialsMatchers.instanceOf(FortifyApiToken.class)); } + @POST public FormValidation doTestConnection(@QueryParameter String url, @QueryParameter String sscTokenCredentialsId, @QueryParameter Boolean isProxy, @QueryParameter Integer connectTimeout, @QueryParameter Integer readTimeout, @QueryParameter Integer writeTimeout) { + checkAdministerPermission(); + return testSscConnection(url, sscTokenCredentialsId, isProxy, connectTimeout, readTimeout, writeTimeout); + } + + private FormValidation testSscConnection(final String url, final String sscTokenCredentialsId, final Boolean isProxy, final Integer connectTimeout, final Integer readTimeout, final Integer writeTimeout) { String sscUrl = url == null ? "" : url.trim(); try { checkUrlValue(sscUrl); @@ -1418,9 +1432,9 @@ public NoReturn runWith(FortifyClient client) throws Exception { } catch (Throwable t) { String message = t.getMessage(); if (message != null && message.contains("Access Denied")) { - return FormValidation.errorWithMarkup("Invalid token. (" + message + ")"); + return FormValidation.error("Invalid token. (" + removeHtmlFormatting(message) + ")"); } - return FormValidation.errorWithMarkup("Cannot connect to SSC server. " + message); + return FormValidation.error("Cannot connect to SSC server. " + removeHtmlFormatting(message)); } finally { this.url = orig_url; setIsProxy(orig_isProxy); @@ -1431,6 +1445,14 @@ public NoReturn runWith(FortifyClient client) throws Exception { } } + private String removeHtmlFormatting(String html) { + if (html != null) { + // we're using the simplest approach here in order not to introduce a new library dependency in this release + return html.replaceAll("<[^>]*>", ""); + } + return ""; + } + private FortifyApiToken getTokenFrom(String tokenId, String url) throws FortifyException { FortifyApiToken c = tokenId == null ? null : CredentialsMatchers.firstOrNull( CredentialsProvider.lookupCredentials(FortifyApiToken.class, Jenkins.get(), ACL.SYSTEM, @@ -1439,6 +1461,7 @@ private FortifyApiToken getTokenFrom(String tokenId, String url) throws FortifyE return c; } + @POST public ListBoxModel doFillCtrlTokenCredentialsIdItems(@AncestorInPath Item item, @QueryParameter String ctrlTokenCredentialsId, @QueryParameter String ctrlUrl) { StandardListBoxModel result = new StandardListBoxModel(); if (item == null) { @@ -1456,7 +1479,9 @@ public ListBoxModel doFillCtrlTokenCredentialsIdItems(@AncestorInPath Item item, CredentialsMatchers.instanceOf(FortifyApiToken.class)); } + @POST public FormValidation doTestCtrlConnection(@QueryParameter String ctrlUrl, @QueryParameter String ctrlTokenCredentialsId, @QueryParameter Boolean isProxy) throws IOException { + checkAdministerPermission(); String controllerUrl = ctrlUrl == null ? "" : ctrlUrl.trim(); try { checkCtrlUrlValue(controllerUrl); @@ -1549,6 +1574,10 @@ private void checkCtrlUrlValue(String ctrlUrl) throws FortifyException { if (ctrlUrl.endsWith("/")) { ctrlUrl = ctrlUrl.substring(0, ctrlUrl.length()-1); } + int hash = ctrlUrl.indexOf("%23"); + if (hash > 0) { + ctrlUrl = ctrlUrl.substring(0, hash); + } if (!StringUtils.endsWith(ctrlUrl,"/scancentral-ctrl") && !StringUtils.endsWith(ctrlUrl,"/cloud-ctrl")) { throw new FortifyException(new Message(Message.ERROR, "Invalid context")); } @@ -1561,7 +1590,13 @@ private void checkCtrlUrlValue(String ctrlUrl) throws FortifyException { } } - public void doRefreshProjects(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) throws Exception { + @POST + public void doRefreshProjects(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value, @AncestorInPath Item item) throws Exception { + if (item != null) { + item.checkPermission(Item.CONFIGURE); + } else { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + } try { String typedText = sanitizeUnicodeControls(req.getParameter("typedText")); // always retrieve data from SSC @@ -1587,7 +1622,13 @@ public void doRefreshProjects(StaplerRequest req, StaplerResponse rsp, @QueryPar } } - public void doRefreshVersions(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) throws Exception { + @POST + public void doRefreshVersions(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value, @AncestorInPath Item item) throws Exception { + if (item != null) { + item.checkPermission(Item.CONFIGURE); + } else { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + } try { String selectedApp = sanitizeUnicodeControls(req.getParameter("selectedPrj")); String typedText = sanitizeUnicodeControls(req.getParameter("typedText")); @@ -1638,7 +1679,9 @@ private String escapeJsonValue(String stringValue) { return stringValue.replace("\"", "\\\""); } + @POST public void doRefreshProjectTemplates(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) throws Exception { + checkAdministerPermission(); // backup original values String orig_url = this.url; ProxyConfig orig_proxyConfig = this.proxyConfig; @@ -1661,7 +1704,7 @@ public void doRefreshProjectTemplates(StaplerRequest req, StaplerResponse rsp, @ this.sscTokenCredentialsId = tokenId; try { - FormValidation testConnectionResult = doTestConnection(this.url, this.getSscTokenCredentialsId(), useProxyParam, connectTimeout, readTimeout, writeTimeout); + FormValidation testConnectionResult = testSscConnection(this.url, this.getSscTokenCredentialsId(), useProxyParam, connectTimeout, readTimeout, writeTimeout); if (!testConnectionResult.kind.equals(FormValidation.Kind.OK)) { LOGGER.log(Level.WARNING, "Can't retrieve Fortify Issue Template list because of SSC server connection problem: " + testConnectionResult.getLocalizedMessage()); return; // don't get templates if server is unavailable @@ -1695,15 +1738,21 @@ public void doRefreshProjectTemplates(StaplerRequest req, StaplerResponse rsp, @ } } + private static void checkAdministerPermission() { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + } + + @POST public void doRefreshSensorPools(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) throws Exception { + checkAdministerPermission(); // backup original values String orig_url = this.url; String url = req.getParameter("url"); this.url = url != null ? url.trim() : ""; try { - FormValidation testConnectionResult = doTestConnection(this.url, this.getSscTokenCredentialsId(), this.getIsProxy(), connectTimeout, readTimeout, writeTimeout); //XXX verify ctrl or ssc token id is needed + FormValidation testConnectionResult = testSscConnection(this.url, this.getSscTokenCredentialsId(), this.getIsProxy(), connectTimeout, readTimeout, writeTimeout); //XXX verify ctrl or ssc token id is needed if (!testConnectionResult.kind.equals(FormValidation.Kind.OK)) { throw new Exception(testConnectionResult.getLocalizedMessage()); // don't get sensor pools if server is unavailable } @@ -1733,7 +1782,13 @@ public void doRefreshSensorPools(StaplerRequest req, StaplerResponse rsp, @Query } } - public void doCreateNewProject(final StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) throws Exception { + @POST + public void doCreateNewProject(final StaplerRequest req, StaplerResponse rsp, @QueryParameter String value, @AncestorInPath Item item) throws Exception { + if (item != null) { + item.checkPermission(Item.CONFIGURE); + } else { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + } try { runWithFortifyClient(getToken(), new FortifyClient.Command<FortifyClient.NoReturn>() { @Override @@ -1749,7 +1804,7 @@ public NoReturn runWith(FortifyClient client) throws Exception { e.printStackTrace(); } - doRefreshProjects(req, rsp, value); + doRefreshProjects(req, rsp, value, item); } private boolean isSettingUpdated = false; @@ -1798,25 +1853,41 @@ public boolean isSettingUpdated() { } } - public ComboBoxModel doFillAppNameItems() { - Map<String, Long> allPrj = getAllProjects(null); + @POST + public ComboBoxModel doFillAppNameItems(@AncestorInPath Item item) { + Map<String, Long> allPrj; + if (item != null) { + item.checkPermission(Item.CONFIGURE); + allPrj = getAllProjects(null); + } else { + allPrj = Collections.emptyMap(); + } return new ComboBoxModel(allPrj.keySet()); } - public ComboBoxModel getAppNameItems() { - return doFillAppNameItems(); + @POST + public ComboBoxModel getAppNameItems(@AncestorInPath Item item) { + return doFillAppNameItems(item); } - public ComboBoxModel doFillAppVersionItems(@QueryParameter String appName) { - Map<String, Long> allPrjVersions = getVersionsFor(appName); - if (null == allPrjVersions) { - return new ComboBoxModel(Collections.<String>emptyList()); + @POST + public ComboBoxModel doFillAppVersionItems(@QueryParameter String appName, @AncestorInPath Item item) { + Map<String, Long> allPrjVersions; + if (item != null) { + item.checkPermission(Item.CONFIGURE); + allPrjVersions = getVersionsFor(appName); + if (null == allPrjVersions) { + return new ComboBoxModel(Collections.<String>emptyList()); + } + } else { + allPrjVersions = Collections.emptyMap(); } return new ComboBoxModel(allPrjVersions.keySet()); } - public ComboBoxModel getAppVersionItems(@QueryParameter String appName) { - return doFillAppVersionItems(appName); + @POST + public ComboBoxModel getAppVersionItems(@QueryParameter String appName, @AncestorInPath Item item) { + return doFillAppVersionItems(appName, item); } private Map<String, Long> getAllProjects(String query) { @@ -1878,11 +1949,15 @@ public Map<String, Long> runWith(FortifyClient client) throws Exception { } } - public AutoCompletionCandidates doAutoCompleteAppName(@QueryParameter String value) { + @POST + public AutoCompletionCandidates doAutoCompleteAppName(@QueryParameter String value, @AncestorInPath Item item) { AutoCompletionCandidates c = new AutoCompletionCandidates(); - for (String nextApp : getAllProjects(value).keySet()) { - if (nextApp.toLowerCase(Locale.ENGLISH).startsWith(value.toLowerCase(Locale.ENGLISH))) { - c.add(nextApp); + if (item != null) { + item.checkPermission(Item.CONFIGURE); + for (String nextApp : getAllProjects(value).keySet()) { + if (nextApp.toLowerCase(Locale.ENGLISH).startsWith(value.toLowerCase(Locale.ENGLISH))) { + c.add(nextApp); + } } } return c; @@ -1895,20 +1970,28 @@ public AutoCompletionCandidates doAutoCompleteAppName(@QueryParameter String val * @return A list of Issue template and ID * @throws ApiException */ - public ComboBoxModel doFillProjectTemplateItems() { - if (projTemplateList.isEmpty()) { - projTemplateList = getProjTemplateListNoCache(); + @POST + public ComboBoxModel doFillProjectTemplateItems(@AncestorInPath Item item) { + List<String> names; + if (item != null) { + item.checkPermission(Item.CONFIGURE); + if (projTemplateList.isEmpty()) { + projTemplateList = getProjTemplateListNoCache(); + } + names = new ArrayList<String>(projTemplateList.size()); + for (ProjectTemplateBean b : projTemplateList) { + names.add(b.getName()); + } + } else { + names = Collections.emptyList(); } - List<String> names = new ArrayList<String>(projTemplateList.size()); - for (ProjectTemplateBean b : projTemplateList) { - names.add(b.getName()); - } return new ComboBoxModel(names); } - public ComboBoxModel getProjectTemplateItems() { - return doFillProjectTemplateItems(); + @POST + public ComboBoxModel getProjectTemplateItems(@AncestorInPath Item item) { + return doFillProjectTemplateItems(item); } public List<ProjectTemplateBean> getProjTemplateListList() { @@ -1950,13 +2033,17 @@ public int compare(ProjectTemplateBean o1, ProjectTemplateBean o2) { return Collections.emptyList(); } - public ListBoxModel doFillFilterSetItems(@QueryParameter String appName, @QueryParameter String appVersion) { + @POST + public ListBoxModel doFillFilterSetItems(@QueryParameter String appName, @QueryParameter String appVersion, @AncestorInPath Item item) { ListBoxModel standardListBoxModel = new ListBoxModel(); - standardListBoxModel.add(""); - Map<String, String> allFilterSets = refreshFilterSetsFor(appName, appVersion); - if (allFilterSets != null) { - for (Map.Entry<String, String> nextFilterSet : allFilterSets.entrySet()) { - standardListBoxModel.add(nextFilterSet.getKey(), nextFilterSet.getValue()); + if (item != null) { + item.checkPermission(Item.CONFIGURE); + standardListBoxModel.add(""); + Map<String, String> allFilterSets = refreshFilterSetsFor(appName, appVersion); + if (allFilterSets != null) { + for (Map.Entry<String, String> nextFilterSet : allFilterSets.entrySet()) { + standardListBoxModel.add(nextFilterSet.getKey(), nextFilterSet.getValue()); + } } } return standardListBoxModel; @@ -1995,16 +2082,17 @@ public Map<String, String> runWith(FortifyClient client) throws Exception { return Collections.emptyMap(); } - public ListBoxModel doFillSensorPoolUUIDItems() { - sensorPoolList = getSensorPoolListNoCache(); - + @POST + public ListBoxModel doFillSensorPoolUUIDItems(@AncestorInPath Item item) { List<ListBoxModel.Option> optionList = new ArrayList<>(); - - for (SensorPoolBean sensorPoolBean : sensorPoolList) { - ListBoxModel.Option option = new ListBoxModel.Option(sensorPoolBean.getName(), sensorPoolBean.getUuid()); - optionList.add(option); + if (item != null) { + item.checkPermission(Item.CONFIGURE); + sensorPoolList = getSensorPoolListNoCache(); + for (SensorPoolBean sensorPoolBean : sensorPoolList) { + ListBoxModel.Option option = new ListBoxModel.Option(sensorPoolBean.getName(), sensorPoolBean.getUuid()); + optionList.add(option); + } } - return new ListBoxModel(optionList); }
src/main/java/com/fortify/plugin/jenkins/steps/CloudScanMbs.java+18 −10 modified@@ -28,11 +28,14 @@ import org.jenkinsci.plugins.workflow.steps.StepDescriptor; import org.jenkinsci.plugins.workflow.steps.StepExecution; import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution; +import hudson.model.Item; +import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; import com.fortify.plugin.jenkins.FortifyPlugin; import com.google.common.collect.ImmutableSet; @@ -247,26 +250,31 @@ public FormValidation doCheckBuildID(@QueryParameter String value) { return Validators.checkFieldNotEmpty(value); } - public void doRefreshProjects(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) + @POST + public void doRefreshProjects(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value, @AncestorInPath Item item) throws Exception { - FortifyPlugin.DESCRIPTOR.doRefreshProjects(req, rsp, value); + FortifyPlugin.DESCRIPTOR.doRefreshProjects(req, rsp, value, item); } - public void doRefreshVersions(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) + @POST + public void doRefreshVersions(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value, @AncestorInPath Item item) throws Exception { - FortifyPlugin.DESCRIPTOR.doRefreshVersions(req, rsp, value); + FortifyPlugin.DESCRIPTOR.doRefreshVersions(req, rsp, value, item); } - public ComboBoxModel doFillAppNameItems() { - return FortifyPlugin.DESCRIPTOR.doFillAppNameItems(); + @POST + public ComboBoxModel doFillAppNameItems(@AncestorInPath Item item) { + return FortifyPlugin.DESCRIPTOR.doFillAppNameItems(item); } - public ComboBoxModel doFillAppVersionItems(@QueryParameter String appName) { - return FortifyPlugin.DESCRIPTOR.doFillAppVersionItems(appName); + @POST + public ComboBoxModel doFillAppVersionItems(@QueryParameter String appName, @AncestorInPath Item item) { + return FortifyPlugin.DESCRIPTOR.doFillAppVersionItems(appName, item); } - public ListBoxModel doFillSensorPoolUUIDItems() { - return FortifyPlugin.DESCRIPTOR.doFillSensorPoolUUIDItems(); + @POST + public ListBoxModel doFillSensorPoolUUIDItems(@AncestorInPath Item item) { + return FortifyPlugin.DESCRIPTOR.doFillSensorPoolUUIDItems(item); } }
src/main/java/com/fortify/plugin/jenkins/steps/CloudScanStart.java+18 −10 modified@@ -22,17 +22,20 @@ import java.util.List; import java.util.Set; +import hudson.model.Item; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.jenkinsci.plugins.workflow.steps.StepContext; import org.jenkinsci.plugins.workflow.steps.StepDescriptor; import org.jenkinsci.plugins.workflow.steps.StepExecution; import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution; +import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; import com.fortify.plugin.jenkins.FortifyPlugin; import com.fortify.plugin.jenkins.steps.remote.GradleProjectType; @@ -372,26 +375,31 @@ public Set<? extends Class<?>> getRequiredContext() { return ImmutableSet.of(Run.class, FilePath.class, EnvVars.class, Launcher.class, TaskListener.class); } - public void doRefreshProjects(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) + @POST + public void doRefreshProjects(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value, @AncestorInPath Item item) throws Exception { - FortifyPlugin.DESCRIPTOR.doRefreshProjects(req, rsp, value); + FortifyPlugin.DESCRIPTOR.doRefreshProjects(req, rsp, value, item); } - public void doRefreshVersions(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) + @POST + public void doRefreshVersions(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value, @AncestorInPath Item item) throws Exception { - FortifyPlugin.DESCRIPTOR.doRefreshVersions(req, rsp, value); + FortifyPlugin.DESCRIPTOR.doRefreshVersions(req, rsp, value, item); } - public ComboBoxModel doFillAppNameItems() { - return FortifyPlugin.DESCRIPTOR.doFillAppNameItems(); + @POST + public ComboBoxModel doFillAppNameItems(@AncestorInPath Item item) { + return FortifyPlugin.DESCRIPTOR.doFillAppNameItems(item); } - public ComboBoxModel doFillAppVersionItems(@QueryParameter String appName) { - return FortifyPlugin.DESCRIPTOR.doFillAppVersionItems(appName); + @POST + public ComboBoxModel doFillAppVersionItems(@QueryParameter String appName, @AncestorInPath Item item) { + return FortifyPlugin.DESCRIPTOR.doFillAppVersionItems(appName, item); } - public ListBoxModel doFillSensorPoolUUIDItems() { - return FortifyPlugin.DESCRIPTOR.doFillSensorPoolUUIDItems(); + @POST + public ListBoxModel doFillSensorPoolUUIDItems(@AncestorInPath Item item) { + return FortifyPlugin.DESCRIPTOR.doFillSensorPoolUUIDItems(item); } }
src/main/java/com/fortify/plugin/jenkins/steps/FortifyUpload.java+18 −10 modified@@ -34,11 +34,13 @@ import org.jenkinsci.plugins.workflow.steps.StepDescriptor; import org.jenkinsci.plugins.workflow.steps.StepExecution; import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution; +import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; import com.fortify.plugin.jenkins.FPRSummary; import com.fortify.plugin.jenkins.FortifyPlugin; @@ -63,6 +65,7 @@ import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.BuildListener; +import hudson.model.Item; import hudson.model.Result; import hudson.model.Run; import hudson.model.StreamBuildListener; @@ -789,24 +792,29 @@ public Set<? extends Class<?>> getRequiredContext() { return ImmutableSet.of(Run.class, FilePath.class, EnvVars.class, Launcher.class, TaskListener.class); } - public ComboBoxModel getApplicationNameItems() { - return FortifyPlugin.DESCRIPTOR.getAppNameItems(); + @POST + public ComboBoxModel getApplicationNameItems(@AncestorInPath Item item) { + return FortifyPlugin.DESCRIPTOR.getAppNameItems(item); } - public ComboBoxModel getApplicationVersionItems(@QueryParameter String applicationName) { - return FortifyPlugin.DESCRIPTOR.getAppVersionItems(applicationName); + @POST + public ComboBoxModel getApplicationVersionItems(@QueryParameter String applicationName, @AncestorInPath Item item) { + return FortifyPlugin.DESCRIPTOR.getAppVersionItems(applicationName, item); } - public void doRefreshApplications(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) throws Exception { - FortifyPlugin.DESCRIPTOR.doRefreshProjects(req, rsp, value); + @POST + public void doRefreshApplications(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value, @AncestorInPath Item item) throws Exception { + FortifyPlugin.DESCRIPTOR.doRefreshProjects(req, rsp, value, item); } - public void doRefreshVersions(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value) throws Exception { - FortifyPlugin.DESCRIPTOR.doRefreshVersions(req, rsp, value); + @POST + public void doRefreshVersions(StaplerRequest req, StaplerResponse rsp, @QueryParameter String value, @AncestorInPath Item item) throws Exception { + FortifyPlugin.DESCRIPTOR.doRefreshVersions(req, rsp, value, item); } - public ListBoxModel doFillFilterSetItems(@QueryParameter String appName, @QueryParameter String appVersion) { - return FortifyPlugin.DESCRIPTOR.doFillFilterSetItems(appName, appVersion); + @POST + public ListBoxModel doFillFilterSetItems(@QueryParameter String appName, @QueryParameter String appVersion, @AncestorInPath Item item) { + return FortifyPlugin.DESCRIPTOR.doFillFilterSetItems(appName, appVersion, item); } public FormValidation doCheckAppName(@QueryParameter String value) {
src/main/java/com/fortify/plugin/jenkins/TableAction.java+7 −2 modified@@ -31,6 +31,7 @@ import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.bind.JavaScriptMethod; +import org.kohsuke.stapler.verb.POST; import com.fortify.plugin.jenkins.bean.IssueBean; import com.fortify.plugin.jenkins.bean.IssueFolderBean; @@ -371,6 +372,7 @@ public synchronized List<IssueFolderBean> getFolders() { return folders; } + @POST public void doSetPageSize(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { String size = req.getParameter("size"); Integer hadValue = (Integer) req.getSession().getAttribute("pageSize"); @@ -399,9 +401,9 @@ public void doSelectedGrouping(StaplerRequest req, StaplerResponse rsp) throws I } - // we removed that functionality because it stopped working with the REST client - // API, need to re-think a little + @POST public void doShowAllNotNew(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { + // we removed that functionality because it stopped working with the REST client API, need to re-think a little String all = req.getParameter("all"); if (StringUtils.isBlank(all)) { return; @@ -422,6 +424,7 @@ public void doShowAllNotNew(StaplerRequest req, StaplerResponse rsp) throws IOEx doAjaxIssues(req, rsp); } + @POST public void doUpdateIssueList(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { String viewName = req.getParameter("folder"); if (StringUtils.isBlank(viewName)) { @@ -446,6 +449,7 @@ public void doUpdateIssueList(StaplerRequest req, StaplerResponse rsp) throws IO doAjaxIssues(req, rsp); } + @POST public void doAjaxIssues(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { Object currView = req.getSession().getAttribute("currentView"); if ("yes".equalsIgnoreCase(req.getParameter("firstTime")) || currView == null) { @@ -468,6 +472,7 @@ public void doAjaxStats(StaplerRequest req, StaplerResponse rsp) throws IOExcept req.getView(this, "issueCountTable.jelly").forward(req, rsp); } + @POST public synchronized void doCheckUpdates(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { long lastChanged = getLastChanged();
src/main/resources/com/fortify/plugin/jenkins/FortifyPlugin/global.jelly+3 −3 modified@@ -27,7 +27,7 @@ <f:section title="Fortify Assessment"> <f:section title="Software Security Center configuration"> <f:entry title="SSC URL" field="url" help="/plugin/fortify/help-sscUrl.html"> - <f:textbox name="url" id="url"/> + <f:textbox name="url" id="url" checkMethod="post"/> </f:entry> <f:entry field="sscTokenCredentialsId" title="Authentication token" help="/plugin/fortify/help-sscAuthToken.html"> @@ -41,7 +41,7 @@ <f:entry title="Issue template" help="/plugin/fortify/help-sscProjTemplate.html"> <script type="text/javascript" src="${rootURL}/plugin/fortify/refresh-projects.js"/> <div style="float:left;width:80%;"> - <f:editableComboBox id="projectTemplate" name="projectTemplate" field="projectTemplate" clazz="setting-input" items="${descriptor.projectTemplateItems}" /> + <f:editableComboBox id="projectTemplate" name="projectTemplate" field="projectTemplate" clazz="setting-input" items="${descriptor.projectTemplateItems}" checkMethod="post"/> </div> <div style="float:left"> <input value="▼" type="button" id="refreshButton" onclick="refreshTemplateList('${rootURL}/descriptor/${descriptor.clazz.name}/refreshProjectTemplates','url,sscTokenCredentialsId,isProxy')" /> @@ -72,7 +72,7 @@ <f:section title="Controller configuration"> <f:entry title="Controller URL" help="/plugin/fortify/help-controllerUrl.html"> - <f:textbox name="ctrlUrl" field="ctrlUrl" id="ctrlUrl"/> + <f:textbox name="ctrlUrl" field="ctrlUrl" id="ctrlUrl" checkMethod="post"/> </f:entry> <f:entry field="ctrlTokenCredentialsId" title="Controller token" help="/plugin/fortify/help-controllerToken.html">
src/main/webapp/refresh-issues.js+25 −15 modified@@ -15,7 +15,7 @@ *******************************************************************************/ var isUpdateEnable = true; - function updateByUrl(boxId,urlLink,spinnerUrl) { + function updateByUrl(boxId,urlLink,params,spinnerUrl) { // first display the "loading..." icon if (isUpdateEnable) { isUpdateEnable = false; @@ -24,6 +24,7 @@ // then actually fetch the HTML new Ajax.Request(urlLink, { method: "post", + parameters: params, onComplete: function(rsp,_) { var issueTable = document.getElementById('issueTable'); if (issueTable != null) { @@ -36,34 +37,40 @@ } function updateList(boxId,folder,nextPage,spinnerUrl) { - updateByUrl(boxId,contextUrl+"/updateIssueList?folder=" + folder + "&page=" + nextPage,spinnerUrl); + var params = {'folder' : folder, 'page' : nextPage}; + updateByUrl(boxId,contextUrl+"/updateIssueList",params,spinnerUrl); } function updateListWithSort(boxId,folder,nextPage,sortOrd,spinnerUrl) { - updateByUrl(boxId,contextUrl+"/updateIssueList?folder=" + folder + "&page=" + nextPage + "&sort=" + sortOrd,spinnerUrl); + var params = {'folder' : folder, 'page' : nextPage, 'sort' : sortOrd}; + updateByUrl(boxId,contextUrl+"/updateIssueList",params,spinnerUrl); } function updatePageSize(boxId,aSize,spinnerUrl) { - updateByUrl(boxId,contextUrl+"/setPageSize?size=" + aSize,spinnerUrl); + var params = {'size' : aSize}; + updateByUrl(boxId,contextUrl+"/setPageSize",params,spinnerUrl); } function showNew(boxId,spinnerUrl) { - updateByUrl(boxId,contextUrl+"/showAllNotNew?all=no",spinnerUrl); + var params = 'all=no'; + updateByUrl(boxId,contextUrl+"/showAllNotNew",params,spinnerUrl); } function showAll(boxId,spinnerUrl) { - updateByUrl(boxId,contextUrl+"/showAllNotNew?all=yes",spinnerUrl); + var params = 'all=yes'; + updateByUrl(boxId,contextUrl+"/showAllNotNew",params,spinnerUrl); } - function showGrouping(boxId,selectedGrouping,spinnerUrl) - { - updateByUrl(boxId,contextUrl+"/selectedGrouping?grouping="+selectedGrouping, spinnerUrl); + function showGrouping(boxId,selectedGrouping,spinnerUrl) { + var params = {'grouping' : selectedGrouping}; + updateByUrl(boxId,contextUrl+"/selectedGrouping",params, spinnerUrl); } function scheduleUpdateCheck() { - var parameters = {}; - new Ajax.Request(contextUrl+"/checkUpdates?stamp="+stamp,{ - method: "get", + var params = 'stamp='+stamp; + new Ajax.Request(contextUrl+"/checkUpdates",{ + method: "post", + parameters: params, onComplete: function(rsp,_) { var update = rsp.getResponseHeader('go'); if(update == "go") { @@ -80,7 +87,7 @@ function reloadStatistics() { var parameters = {}; new Ajax.Request(contextUrl+"/ajaxStats",{ - method: "get", + method: "post", onComplete: function(rsp,_) { var scanStatistics = document.getElementById('scanStatistics'); if (scanStatistics != null) { @@ -93,6 +100,7 @@ function reloadIssues() { var parameters = {}; new Ajax.Request(contextUrl+"/ajaxIssues",{ + method: "post", parameters: parameters, onComplete: function(rsp) { var issueTable = document.getElementById('issueTable'); @@ -106,6 +114,7 @@ function reload(url,box) { var parameters = {}; new Ajax.Request(url,{ + method: "post", parameters: parameters, onComplete: function(rsp) { var issueTable = document.getElementById(box); @@ -122,8 +131,9 @@ var box = document.getElementById('firstTimeSpinF'); box.innerHTML = '<img src="'+spinnerUrl+'" alt=""/>'; // then actually fetch the HTML - var request = new Ajax.Request(contextUrl+"/ajaxIssues?firstTime=yes",{ - method: "get", + var request = new Ajax.Request(contextUrl+"/ajaxIssues",{ + method: "post", + parameters : "firstTime=yes", onComplete: function(rsp,_) { var issueTable = document.getElementById('issueTable'); issueTable.innerHTML = rsp.responseText;
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-3fjv-8r82-6xm9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-4301ghsaADVISORY
- www.jenkins.io/security/advisory/2023-08-16/ghsavendor-advisoryWEB
- github.com/jenkinsci/fortify-plugin/commit/357d7bfbcb0ff796ea7d078bee13159f1d000f5dghsaWEB
News mentions
1- Jenkins Security Advisory 2023-08-16Jenkins Security Advisories · Aug 16, 2023