Security context
Medium· 5.4GHSA-q6q9-83xw-mp6p CVE-2019-10402CWE-79Published May 24, 2022

Improper Neutralization of Input During Web Page Generation in Jenkins

Research this vulnerability

Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.

Affected versions

0 → fixed in 2.176.42.177 → fixed in 2.197

Details

In Jenkins 2.196 and earlier, LTS 2.176.3 and earlier, the f:combobox form control interpreted its item labels as HTML, resulting in a stored XSS vulnerability exploitable by users with permission to define its contents.

The fix

[SECURITY-1525]

Wadeck Follonier· Sep 10, 2019, 07:27 PM+57100064be366
test/src/test/java/lib/form/ComboBoxSEC1525Test.java+50 0
@@ -0,0 +1,50 @@
+package lib.form;
+
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import com.gargoylesoftware.htmlunit.html.HtmlElementUtil;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import hudson.model.FreeStyleProject;
+import hudson.model.Job;
+import hudson.util.ComboBoxModel;
+import jenkins.model.OptionalJobProperty;
+import org.jvnet.hudson.test.HudsonTestCase;
+import org.jvnet.hudson.test.Issue;
+import org.jvnet.hudson.test.TestExtension;
+
+//TODO meant to be merged back into ComboBoxTest after security release to avoid conflict during the upmerge process
+public class ComboBoxSEC1525Test extends HudsonTestCase {
+ public static class XssProperty extends OptionalJobProperty<Job<?,?>> {
+ @TestExtension("testEnsureXSSnotPossible")
+ public static class DescriptorImpl extends OptionalJobProperty.OptionalJobPropertyDescriptor {
+
+ @Override
+ public String getDisplayName() {
+ return "XSS Property";
+ }
+
+ public ComboBoxModel doFillXssItems() {
+ return new ComboBoxModel("<h1>HACK</h1>");
+ }
+ }
+ }
+
+ @Issue("SECURITY-1525")
+ public void testEnsureXSSnotPossible() throws Exception {
+ XssProperty xssProperty = new XssProperty();
+ FreeStyleProject p = createFreeStyleProject();
+ p.addProperty(xssProperty);
+
+ WebClient wc = new WebClient();
+
+ HtmlPage configurePage = wc.getPage(p, "configure");
+ int numberOfH1Before = configurePage.getElementsByTagName("h1").size();
+
+ HtmlElement comboBox = configurePage.getElementByName("_.xss");
+ HtmlElementUtil.click(comboBox);
+
+ // no additional h1, meaning the "payload" is not interpreted
+ int numberOfH1After = configurePage.getElementsByTagName("h1").size();
+
+ assertEquals(numberOfH1Before, numberOfH1After);
+ }
+}
test/src/test/resources/lib/form/ComboBoxSEC1525Test/XssProperty/config.jelly+6 0
@@ -0,0 +1,6 @@
+<?jelly escape-by-default='true'?>
+<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
+ <f:entry field="xss">
+ <f:combobox />
+ </f:entry>
+</j:jelly>
war/src/main/webapp/scripts/combobox.js+1 1
@@ -246,7 +246,7 @@ ComboBox.prototype.populateDropdown = function() {
for (var i = 0; i < this.availableItems.length; i++) {
var item = document.createElement("div");
item.className = "comboBoxItem";
- item.innerHTML = this.availableItems[i];
+ item.innerText = this.availableItems[i];
item.id = "item_" + this.availableItems[i];
item.comboBox = this;
item.comboBoxIndex = i;

References