Security context
High· 8.0GHSA-gfhj-524q-gcrm CVE-2020-2223CWE-79Published May 24, 2022

Stored XSS vulnerability in Jenkins console links

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 `href` attribute of links to downstream jobs displayed in the build console page. This results in a stored cross-site scripting (XSS) vulnerability exploitable by users with Job/Configure permission. Jenkins 2.245, LTS 2.235.2 escapes the `href` attribute of these links.

The fix

[SECURITY-1945]

"Singh, Abhinav Kumar"· Jul 6, 2020, 02:34 PM+20111f4a35122
core/src/main/java/hudson/console/HyperlinkNote.java+2 1
@@ -25,6 +25,7 @@
import hudson.Extension;
import hudson.MarkupText;
+import hudson.Util;
import jenkins.model.Jenkins;
import org.jenkinsci.Symbol;
import org.kohsuke.accmod.Restricted;
@@ -69,7 +70,7 @@ public ConsoleAnnotator annotate(Object context, MarkupText text, int charPos) {
url = Jenkins.get().getRootUrl()+url.substring(1);
}
}
- text.addMarkup(charPos, charPos + length, "<a href='" + url + "'"+extraAttributes()+">", "</a>");
+ text.addMarkup(charPos, charPos + length, "<a href='" + Util.escape(url) + "'"+extraAttributes()+">", "</a>");
return null;
}
test/src/test/java/hudson/console/HyperlinkNoteTest.java+18 0
@@ -24,11 +24,16 @@
package hudson.console;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
+
+import hudson.model.Result;
+import hudson.tasks.BuildTrigger;
import org.apache.commons.io.IOUtils;
import org.junit.Rule;
import org.junit.Test;
@@ -73,6 +78,19 @@ public void textWithNewlinesModelHyperlinkNote() throws Exception {
containsString(">" + noteTextSanitized + "</a>")));
}
+ @Test
+ public void textWithSingleQuote() throws Exception {
+ FreeStyleProject upstream = r.createFreeStyleProject("upstream");
+ r.createFreeStyleProject("d0wnstr3'am");
+ upstream.getPublishersList().add(new BuildTrigger("d0wnstr3'am", Result.SUCCESS));
+ r.jenkins.rebuildDependencyGraph();
+ FreeStyleBuild b = r.buildAndAssertSuccess(upstream);
+ r.waitUntilNoActivity();
+ HtmlPage rsp = r.createWebClient().goTo(b.getUrl()+"console");
+ assertThat(rsp.querySelector(".console-output").asText(), containsString("Triggering a new build of"));
+ assertThat(String.valueOf(rsp.getAnchorByText("d0wnstr3'am").click().getWebResponse().getStatusCode()), containsString("200"));
+ }
+
private static String annotate(String text) throws IOException {
StringWriter writer = new StringWriter();
try (ConsoleAnnotationOutputStream out = new ConsoleAnnotationOutputStream(writer, null, null, StandardCharsets.UTF_8)) {

References