Security context
High· 8.0GHSA-qgj4-rc8m-44mq CVE-2020-2220CWE-79Published May 24, 2022

Stored XSS vulnerability in Jenkins job build time trend

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.235.22.236 → fixed in 2.245

Details

Jenkins 2.244 and earlier, LTS 2.235.1 and earlier does not escape the agent name in the build time trend page, resulting in a stored cross-site scripting vulnerability. Jenkins 2.245, LTS 2.235.2 escapes the agent name.

The fix

[SECURITY-1868]

Wadeck Follonier· Jun 30, 2020, 02:55 PM+1011b43531acee
core/src/main/resources/hudson/model/Job/buildTimeTrend.jelly+1 1
@@ -55,7 +55,7 @@ THE SOFTWARE.
update(e.durationString.escapeHTML()));
<j:if test="${isMasterSlaveEnabled}">
tr.insert(new Element('td').
- update(e.builtOn ? new Element('a', {href: '${rootURL}/computer/' + e.builtOn, 'class': 'model-link inside'}).update(e.builtOnStr) : e.builtOnStr));
+ update(e.builtOn ? new Element('a', {href: '${rootURL}/computer/' + e.builtOn, 'class': 'model-link inside'}).update(e.builtOnStr.escapeHTML()) : e.builtOnStr.escapeHTML()));
</j:if>
p.insert(tr);
Behaviour.applySubtree(tr);
test/src/test/java/hudson/model/JobSEC1868Test.java+100 0
@@ -0,0 +1,100 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
+ * Copyright (c) 2015 Christopher Simons
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package hudson.model;
+
+import hudson.slaves.RetentionStrategy;
+import org.junit.Rule;
+import org.junit.Test;
+import org.jvnet.hudson.test.Issue;
+import org.jvnet.hudson.test.JenkinsRule;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+//TODO to be merged with JobTest after security release
+public class JobSEC1868Test {
+
+ @Rule public JenkinsRule j = new JenkinsRule();
+
+ @Issue("SECURITY-1868")
+ @Test public void noXssPossible() throws Exception {
+ String desiredNodeName = "agent is a better name2 <script>alert(123)</script>";
+ String initialNodeName = "agent is a better name";
+
+ NameChangingNode node = new NameChangingNode(j, initialNodeName);
+ j.jenkins.addNode(node);
+
+ j.waitOnline(node);
+
+ j.jenkins.setNumExecutors(0);
+
+ FreeStyleProject p = j.createFreeStyleProject();
+ j.assertBuildStatusSuccess(p.scheduleBuild2(0));
+
+ node.setVirtualName(desiredNodeName);
+
+ JenkinsRule.WebClient wc = j.createWebClient();
+ AtomicReference<String> alertContent = new AtomicReference<>("");
+
+ wc.setAlertHandler((page, s1) ->
+ alertContent.set(s1)
+ );
+
+ wc.withThrowExceptionOnFailingStatusCode(false);
+ wc.getPage(p, "buildTimeTrend");
+
+ assertEquals("", alertContent.get());
+ }
+
+ /**
+ * This special class was created just to avoid running the test on unix only
+ * as the only limitation is the file path, if we change only the name, the XSS is possible also under windows
+ */
+ static class NameChangingNode extends Slave {
+ private String virtualName;
+
+ public NameChangingNode(JenkinsRule j, String name) throws Exception {
+ super(name, "dummy", j.createTmpDir().getPath(), "1", Node.Mode.NORMAL, "", j.createComputerLauncher(null), RetentionStrategy.NOOP, new ArrayList<>());
+ }
+
+ public void setVirtualName(String virtualName) {
+ this.virtualName = virtualName;
+ }
+
+ @Override
+ public String getNodeName() {
+ if (virtualName != null) {
+ return virtualName;
+ } else {
+ return super.getNodeName();
+ }
+ }
+ }
+}

References