Stored XSS vulnerability in Jenkins job build time trend
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]
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
- ADVISORYhttps://nvd.nist.gov/vuln/detail/CVE-2020-2220
- WEBhttps://github.com/jenkinsci/jenkins/commit/b43531acee280dedc3ea454a2fc5a1a42990ddda
- PACKAGEhttps://github.com/jenkinsci/jenkins
- WEBhttps://jenkins.io/security/advisory/2020-07-15/#SECURITY-1868
- WEBhttp://www.openwall.com/lists/oss-security/2020/07/15/5