Security context
Medium· 5.4GHSA-jpvq-v729-7j2h CVE-2020-2231CWE-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.235.42.237 → fixed in 2.252

Details

Jenkins 2.251 and earlier, LTS 2.235.3 and earlier does not escape the remote address of the host starting a build via 'Trigger builds remotely', resulting in a stored cross-site scripting (XSS) vulnerability exploitable by users with Job/Configure permission or knowledge of the Authentication Token.

The fix

[SECURITY-1960]

Daniel Beck· Jul 29, 2020, 08:54 AM+80229c9a8fdea
core/src/main/java/hudson/model/Cause.java+2 2
@@ -486,12 +486,12 @@ public RemoteCause(String host, String note) {
public String getShortDescription() {
if(note != null) {
try {
- return Messages.Cause_RemoteCause_ShortDescriptionWithNote(addr, Jenkins.get().getMarkupFormatter().translate(note));
+ return Messages.Cause_RemoteCause_ShortDescriptionWithNote(Util.xmlEscape(addr), Jenkins.get().getMarkupFormatter().translate(note));
} catch (IOException x) {
// ignore
}
}
- return Messages.Cause_RemoteCause_ShortDescription(addr);
+ return Messages.Cause_RemoteCause_ShortDescription(Util.xmlEscape(addr));
}
@Exported(visibility = 3)
test/src/test/java/hudson/model/CauseSecurity1960Test.java+32 0
@@ -0,0 +1,32 @@
+package hudson.model;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.jvnet.hudson.test.Issue;
+import org.jvnet.hudson.test.JenkinsRule;
+import org.jvnet.hudson.test.recipes.LocalData;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+
+// TODO merge into CauseTest after release
+public class CauseSecurity1960Test {
+ @Rule
+ public JenkinsRule j = new JenkinsRule();
+
+ @Test
+ @Issue("SECURITY-1960")
+ @LocalData
+ public void xssInRemoteCause() throws IOException, SAXException {
+ final Item item = j.jenkins.getItemByFullName("fs");
+ Assert.assertTrue(item instanceof FreeStyleProject);
+ FreeStyleProject fs = (FreeStyleProject) item;
+ final FreeStyleBuild build = fs.getBuildByNumber(1);
+
+ final JenkinsRule.WebClient wc = j.createWebClient();
+ final String content = wc.getPage(build).getWebResponse().getContentAsString();
+ Assert.assertFalse(content.contains("Started by remote host <img"));
+ Assert.assertTrue(content.contains("Started by remote host &lt;img"));
+ }
+}
test/src/test/resources/hudson/model/CauseSecurity1960Test/jobs/fs/builds/1/build.xml+28 0
@@ -0,0 +1,28 @@
+<?xml version='1.1' encoding='UTF-8'?>
+<build>
+ <actions>
+ <hudson.model.CauseAction>
+ <causeBag class="linked-hash-map">
+ <entry>
+ <hudson.model.Cause_-RemoteCause>
+ <addr>&lt;img src=x onerror=alert(1)&gt;</addr>
+ <note>note</note>
+ </hudson.model.Cause_-RemoteCause>
+ <int>1</int>
+ </entry>
+ </causeBag>
+ </hudson.model.CauseAction>
+ </actions>
+ <queueId>4</queueId>
+ <timestamp>1595937941553</timestamp>
+ <startTime>1595937941557</startTime>
+ <result>SUCCESS</result>
+ <duration>2</duration>
+ <charset>UTF-8</charset>
+ <keepLog>false</keepLog>
+ <builtOn></builtOn>
+ <workspace>/var/jenkins_home/workspace/fs</workspace>
+ <hudsonVersion>2.249</hudsonVersion>
+ <scm class="hudson.scm.NullChangeLogParser"/>
+ <culprits class="com.google.common.collect.EmptyImmutableSortedSet"/>
+</build>
test/src/test/resources/hudson/model/CauseSecurity1960Test/jobs/fs/config.xml+18 0
@@ -0,0 +1,18 @@
+<?xml version='1.1' encoding='UTF-8'?>
+<project>
+ <actions/>
+ <description></description>
+ <keepDependencies>false</keepDependencies>
+ <properties/>
+ <scm class="hudson.scm.NullSCM"/>
+ <canRoam>true</canRoam>
+ <disabled>false</disabled>
+ <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
+ <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
+ <authToken>test</authToken>
+ <triggers/>
+ <concurrentBuild>false</concurrentBuild>
+ <builders/>
+ <publishers/>
+ <buildWrappers/>
+</project>

References