CVE-2023-27898
Description
Jenkins 2.270 through 2.393 (both inclusive), LTS 2.277.1 through 2.375.3 (both inclusive) does not escape the Jenkins version a plugin depends on when rendering the error message stating its incompatibility with the current version of Jenkins, resulting in a stored cross-site scripting (XSS) vulnerability exploitable by attackers able to provide plugins to the configured update sites and have this message shown by Jenkins instances.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Jenkins fails to escape plugin dependency version in error messages, enabling stored XSS via malicious plugins on update sites.
CVE-2023-27898 is a stored cross-site scripting (XSS) vulnerability in Jenkins core, versions 2.270 through 2.393 and LTS 2.277.1 through 2.375.3. The flaw exists because Jenkins does not escape the Jenkins version a plugin depends on when rendering an error message about incompatibility with the current Jenkins version [1][2].
To exploit this vulnerability, an attacker must be able to provide plugins to the configured update sites, such as by controlling a custom update site or by having the instance show outdated plugin metadata (e.g., after a downgrade). The vulnerable error message appears in the plugin manager when a plugin's required Jenkins version is higher than the current version. Notably, exploitation does not require the manipulated plugin to be installed [1].
Successful exploitation results in stored XSS, allowing the attacker to execute arbitrary JavaScript in the context of the Jenkins web interface. This can lead to credential theft, configuration changes, or further compromise of the Jenkins instance and its builds [1].
The vulnerability is fixed in Jenkins 2.394, LTS 2.375.4, and LTS 2.387.1 [1][3]. For many up-to-date instances, the vulnerable message is not shown because the official update site only returns compatible plugins. However, instances using custom update sites or older versions are at risk. Users should update Jenkins core immediately.
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.main:jenkins-coreMaven | >= 2.376, < 2.394 | 2.394 |
org.jenkins-ci.main:jenkins-coreMaven | < 2.375.4 | 2.375.4 |
Affected products
9- osv-coords8 versionspkg:apk/chainguard/jenkinspkg:apk/chainguard/jenkins-compatpkg:apk/chainguard/jenkins-remotingpkg:apk/wolfi/jenkinspkg:apk/wolfi/jenkins-compatpkg:apk/wolfi/jenkins-remotingpkg:bitnami/jenkinspkg:maven/org.jenkins-ci.main/jenkins-core
< 2.395-r0+ 7 more
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: >= 2.270.0, < 2.394.0
- (no CPE)range: >= 2.376, < 2.394
- Jenkins Project/Jenkinsv5Range: 2.270
Patches
13 files changed · +172 −2
core/src/main/java/hudson/PluginManager.java+6 −2 modified@@ -1469,7 +1469,11 @@ public HttpResponse doPluginsSearch(@QueryParameter String query, @QueryParamete jsonObject.put("sourceId", plugin.sourceId); jsonObject.put("title", plugin.title); jsonObject.put("displayName", plugin.getDisplayName()); - jsonObject.put("wiki", plugin.wiki); + if (plugin.wiki == null || !(plugin.wiki.startsWith("https://") || plugin.wiki.startsWith("http://"))) { + jsonObject.put("wiki", StringUtils.EMPTY); + } else { + jsonObject.put("wiki", plugin.wiki); + } jsonObject.put("categories", plugin.getCategoriesStream() .filter(PluginManager::isNonMetaLabel) .map(UpdateCenter::getCategoryDisplayName) @@ -1486,7 +1490,7 @@ public HttpResponse doPluginsSearch(@QueryParameter String query, @QueryParamete jsonObject.put("version", plugin.version); jsonObject.put("popularity", plugin.popularity); if (plugin.isForNewerHudson()) { - jsonObject.put("newerCoreRequired", Messages.PluginManager_coreWarning(plugin.requiredCore)); + jsonObject.put("newerCoreRequired", Messages.PluginManager_coreWarning(Util.xmlEscape(plugin.requiredCore))); } if (plugin.hasWarnings()) { JSONObject unresolvedSecurityWarnings = new JSONObject();
test/src/test/java/hudson/PluginManagerSecurity3037Test.java+101 −0 added@@ -0,0 +1,101 @@ +package hudson; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.gargoylesoftware.htmlunit.AlertHandler; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.html.HtmlAnchor; +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import hudson.model.DownloadService; +import hudson.model.RootAction; +import hudson.model.UpdateSite; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.servlet.ServletException; +import jenkins.model.Jenkins; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.FlagRule; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.TestExtension; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; + +public class PluginManagerSecurity3037Test { + @Rule + public JenkinsRule r = new JenkinsRule(); + + @Rule + public FlagRule<Boolean> signatureCheck = new FlagRule<>(() -> DownloadService.signatureCheck, x -> DownloadService.signatureCheck = x); + + @Test + public void noInjectionOnAvailablePluginsPage() throws Exception { + DownloadService.signatureCheck = false; + Jenkins.get().getUpdateCenter().getSites().clear(); + UpdateSite us = new UpdateSite("Security3037", Jenkins.get().getRootUrl() + "security3037UpdateCenter/update-center.json"); + Jenkins.get().getUpdateCenter().getSites().add(us); + + try (JenkinsRule.WebClient wc = r.createWebClient()) { + HtmlPage p = wc.goTo("pluginManager"); + List<HtmlElement> elements = p.getElementById("bottom-sticker") + .getElementsByTagName("a") + .stream() + .filter(link -> link.getAttribute("href").equals("checkUpdatesServer")) + .collect(Collectors.toList()); + assertEquals(1, elements.size()); + AlertHandlerImpl alertHandler = new AlertHandlerImpl(); + wc.setAlertHandler(alertHandler); + + HtmlElementUtil.click(elements.get(0)); + HtmlPage available = wc.goTo("pluginManager/available"); + assertTrue(available.querySelector(".alert-danger") + .getTextContent().contains("This plugin is built for Jenkins 2.999")); + wc.waitForBackgroundJavaScript(100); + + HtmlAnchor anchor = available.querySelector(".jenkins-table__link"); + anchor.click(true, false, false); + wc.waitForBackgroundJavaScript(100); + assertTrue(alertHandler.messages.isEmpty()); + } + } + + static class AlertHandlerImpl implements AlertHandler { + List<String> messages = Collections.synchronizedList(new ArrayList<>()); + + @Override + public void handleAlert(final Page page, final String message) { + messages.add(message); + } + } + + @TestExtension("noInjectionOnAvailablePluginsPage") + public static final class Security3037UpdateCenter implements RootAction { + + @Override + public String getIconFileName() { + return "gear2.png"; + } + + @Override + public String getDisplayName() { + return "security-3037-update-center"; + } + + @Override + public String getUrlName() { + return "security3037UpdateCenter"; + } + + public void doDynamic(StaplerRequest staplerRequest, StaplerResponse staplerResponse) throws ServletException, IOException { + staplerResponse.setContentType("application/json"); + staplerResponse.setStatus(200); + staplerResponse.serveFile(staplerRequest, PluginManagerSecurity3037Test.class.getResource("PluginManagerSecurity3037Test/update-center.json")); + } + } +}
test/src/test/resources/hudson/PluginManagerSecurity3037Test/update-center.json+65 −0 added@@ -0,0 +1,65 @@ +updateCenter.post( +{ + "connectionCheckUrl": "https://www.google.com/", + "core": { + "buildDate": "Jan 31, 2023", + "name": "core", + "sha1": "TO8l3+wqx2hWtLWMHjmIOj+ERsk=", + "sha256": "BrXTCwJse5e6b/shXjv5edRJQRjxfJ/GbNrhgYcrZoU=", + "size": 98362341, + "url": "https://updates.jenkins.io/download/war/2.389/jenkins.war", + "version": "2.389" + }, + "generationTimestamp": "2023-02-03T11:04:30Z", + "id": "Security3037", + "deprecations": [], + "plugins": { + "workflow-aggregator": { + "buildDate": "Jun 29, 2022", + "defaultBranch": "master", + "dependencies": [ + { + "name": "pipeline-groovy-lib<img src=x onerror=alert(1)>", + "optional": false, + "version": "591.v3a_7f422b_d058<img src=x onerror=alert(1)>" + } + ], + "developers": [ + { + "developerId": "johndoe<img src=x onerror=alert(1)>", + "name": "john doe<img src=x onerror=alert(1)>" + } + ], + "excerpt": "A suite of plugins that lets you orchestrate automation, simple or complex. See <a href=\"https://www.jenkins.io/solutions/pipeline/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Pipeline as Code with Jenkins</a> for more details.", + "gav": "org.jenkins-ci.plugins.workflow:workflow-aggregator:590.v6a_d052e5a_a_b_5<img src=x onerror=alert(1)>", + "issueTrackers": [ + { + "reportUrl": "https://www.jenkins.io/participate/report-issue/redirect/#21710<img src=x onerror=alert(1)>", + "type": "jira<img src=x onerror=alert(1)>", + "viewUrl": "https://issues.jenkins.io/issues/?jql=component=21710<img src=x onerror=alert(1)>" + } + ], + "labels": [ + "cli<img src=x onerror=alert(1)>", + "misc", + "slaves", + "trigger" + ], + "name": "workflow-aggregator<img src=x onerror=alert(1)>", + "popularity": 256809, + "previousTimestamp": "2022-05-24T12:27:03.00Z<img src=x onerror=alert(1)>", + "previousVersion": "<img src=x onerror=alert(1)>581.v0c46fa_697ffd", + "releaseTimestamp": "2022-06-29T21:02:16.00Z<img src=x onerror=alert(1)>", + "requiredCore": "2.999<img src=x onerror=alert(1)>", + "scm": "https://github.com/jenkinsci/workflow-aggregator-plugin<img src=x onerror=alert(1)>", + "sha1": "6iNlKTnXvr4W+9Svwy1+ctyqgvo=<img src=x onerror=alert(1)>", + "sha256": "P0SFgnqOBFZjxkdKORiQUbrhdlfW5YU7tOpe85bfGWE=<img src=x onerror=alert(1)>", + "size": 8282, + "title": "Pipeline<img src=x onerror=alert(1)>", + "url": "https://updates.jenkins.io/download/plugins/workflow-aggregator/590.v6a_d052e5a_a_b_5/workflow-aggregator.hpi", + "version": "590.v6a_d052e5a_a_b_5<img src=x onerror=alert(1)>", + "wiki": "javascript:alert(1)" + } + }, + "updateCenterVersion": "1" +});
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-j664-qhh4-hpf8ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-27898ghsaADVISORY
- www.jenkins.io/security/advisory/2023-03-08/ghsavendor-advisoryWEB
- github.com/jenkinsci/jenkins/commit/59ac866d9946d7c296023da0ea78baafd4cf71ebghsaWEB
News mentions
1- Jenkins Security Advisory 2023-03-08Jenkins Security Advisories · Mar 8, 2023